﻿///////////////////////////////////////////////////////////////////////////////////////////////////////
// Copyright (c) 2023, ООО 1С-Софт
// Все права защищены. Эта программа и сопроводительные материалы предоставляются 
// в соответствии с условиями лицензии Attribution 4.0 International (CC BY 4.0)
// Текст лицензии доступен по ссылке:
// https://creativecommons.org/licenses/by/4.0/legalcode
///////////////////////////////////////////////////////////////////////////////////////////////////////

#Область СлужебныйПрограммныйИнтерфейс

// Создает профиль переданной почты для подключения к почтовому серверу.
// 
// Параметры:
//  УчетнаяЗапись - СправочникСсылка.УчетныеЗаписиЭлектроннойПочты
//
// Возвращаемое значение:
//  ИнтернетПочтовыйПрофиль - профиль учетной записи;
//  Неопределено - не удалось получить учетную запись по ссылке.
//
Функция ИнтернетПочтовыйПрофиль(УчетнаяЗапись, ДляПолучения = Ложь) Экспорт
	
	ТекстЗапроса =
	"ВЫБРАТЬ РАЗРЕШЕННЫЕ
	|	УчетныеЗаписиЭлектроннойПочты.СерверВходящейПочты КАК АдресСервераIMAP,
	|	УчетныеЗаписиЭлектроннойПочты.ПортСервераВходящейПочты КАК ПортIMAP,
	|	УчетныеЗаписиЭлектроннойПочты.ИспользоватьЗащищенноеСоединениеДляВходящейПочты КАК ИспользоватьSSLIMAP,
	|	УчетныеЗаписиЭлектроннойПочты.Пользователь КАК ПользовательIMAP,
	|	УчетныеЗаписиЭлектроннойПочты.СерверВходящейПочты КАК АдресСервераPOP3,
	|	УчетныеЗаписиЭлектроннойПочты.ПортСервераВходящейПочты КАК ПортPOP3,
	|	УчетныеЗаписиЭлектроннойПочты.ИспользоватьЗащищенноеСоединениеДляВходящейПочты КАК ИспользоватьSSLPOP3,
	|	УчетныеЗаписиЭлектроннойПочты.Пользователь КАК Пользователь,
	|	УчетныеЗаписиЭлектроннойПочты.СерверИсходящейПочты КАК АдресСервераSMTP,
	|	УчетныеЗаписиЭлектроннойПочты.ПортСервераИсходящейПочты КАК ПортSMTP,
	|	УчетныеЗаписиЭлектроннойПочты.ИспользоватьЗащищенноеСоединениеДляИсходящейПочты КАК ИспользоватьSSLSMTP,
	|	УчетныеЗаписиЭлектроннойПочты.ТребуетсяВходНаСерверПередОтправкой КАК POP3ПередSMTP,
	|	УчетныеЗаписиЭлектроннойПочты.Пользователь КАК ПользовательSMTP,
	|	УчетныеЗаписиЭлектроннойПочты.ВремяОжидания КАК Таймаут,
	|	УчетныеЗаписиЭлектроннойПочты.ПротоколВходящейПочты КАК Протокол,
	|	УчетныеЗаписиЭлектроннойПочты.ПриОтправкеПисемТребуетсяАвторизация КАК ПриОтправкеПисемТребуетсяАвторизация,
	|	УчетныеЗаписиЭлектроннойПочты.АвторизацияСПомощьюПочтовогоСервиса
	|ИЗ
	|	Справочник.УчетныеЗаписиЭлектроннойПочты КАК УчетныеЗаписиЭлектроннойПочты
	|ГДЕ
	|	УчетныеЗаписиЭлектроннойПочты.Ссылка = &Ссылка";
	
	Запрос = Новый Запрос(ТекстЗапроса);
	Запрос.УстановитьПараметр("Ссылка", УчетнаяЗапись);
	Выборка = Запрос.Выполнить().Выбрать();
	
	Результат = Неопределено;
	Если Выборка.Следующий() Тогда
		СписокСвойствIMAP = "ИспользоватьSSLIMAP,АдресСервераIMAP,ПортIMAP,ПользовательIMAP";
		СписокСвойствPOP3 = "АдресСервераPOP3,ПортPOP3,ИспользоватьSSLPOP3,Пользователь";
		СписокСвойствSMTP = "АдресСервераSMTP,ПортSMTP,ИспользоватьSSLSMTP";
		
		УстановитьПривилегированныйРежим(Истина);
		Пароли = ОбщегоНазначения.ПрочитатьДанныеИзБезопасногоХранилища(УчетнаяЗапись, 
			"Пароль,ПарольSMTP,ТокенДоступа,СрокДействияТокенаДоступа,ТокенОбновления");
		УстановитьПривилегированныйРежим(Ложь);
		
		Результат = Новый ИнтернетПочтовыйПрофиль;

		Если Выборка.АвторизацияСПомощьюПочтовогоСервиса Тогда
			Если ЗначениеЗаполнено(Пароли.СрокДействияТокенаДоступа) И Пароли.СрокДействияТокенаДоступа - 60 <= ТекущаяДатаСеанса() Тогда
				Пароли.ТокенДоступа = ОбновитьТокенДоступа(УчетнаяЗапись, Пароли.ТокенОбновления);
			КонецЕсли;
			Результат.ТокенДоступа = Пароли.ТокенДоступа;
		КонецЕсли;
		
		Если ДляПолучения Тогда
			Если Выборка.Протокол = "IMAP" Тогда
				ТребуемыеСвойства = СписокСвойствIMAP;
				Результат.ПарольIMAP = Пароли.Пароль;
			Иначе
				ТребуемыеСвойства = СписокСвойствPOP3;
				Результат.Пароль = Пароли.Пароль;
			КонецЕсли;
		Иначе
			ТребуемыеСвойства = СписокСвойствSMTP;
			Если Выборка.ПриОтправкеПисемТребуетсяАвторизация И Не Выборка.POP3ПередSMTP Тогда
				ТребуемыеСвойства = ТребуемыеСвойства + ",ПользовательSMTP";
			КонецЕсли;
			Результат.ПарольSMTP = Пароли.ПарольSMTP;
			Если Выборка.Протокол <> "IMAP" И Выборка.POP3ПередSMTP Тогда
				ТребуемыеСвойства = ТребуемыеСвойства + ",POP3ПередSMTP," + СписокСвойствPOP3;
				Результат.Пароль = Пароли.Пароль;
			КонецЕсли;
			Если Выборка.Протокол = "IMAP" Тогда
				ТребуемыеСвойства = ТребуемыеСвойства + "," + СписокСвойствIMAP;
				Результат.ПарольIMAP =Пароли.Пароль;
			КонецЕсли;
		КонецЕсли;
		ТребуемыеСвойства = ТребуемыеСвойства + ",Таймаут";
		
		СтруктураТребуемыхСвойств = Новый Структура(ТребуемыеСвойства);
		ЗаполнитьЗначенияСвойств(СтруктураТребуемыхСвойств, Выборка);
		Для Каждого СвойствоПрофиля Из СтруктураТребуемыхСвойств Цикл
			Если СтрНайти(СвойствоПрофиля.Ключ, "Сервер") <> 0
				Или СтрНачинаетсяС(СвойствоПрофиля.Ключ, "Пользователь") Тогда
				СтруктураТребуемыхСвойств.Вставить(СвойствоПрофиля.Ключ, СтрокаВPunycode(СвойствоПрофиля.Значение));
			КонецЕсли;
		КонецЦикла;
		
		ЗаполнитьЗначенияСвойств(Результат, СтруктураТребуемыхСвойств);
		Если Результат.ПользовательSMTP = "" Тогда
			Результат.ПарольSMTP = "";
		КонецЕсли;
	КонецЕсли;
	
	Если Результат.ПарольIMAP = "" Тогда
		Результат.ПарольIMAP = Результат.ПарольSMTP;
	КонецЕсли;
	
	Возврат Результат;
	
КонецФункции

// Функция необходима для интеграции с подсистемой "Обмен данными".
// Возвращает настройки электронной почты этой базы, соответствующие настройкам
// электронной почты базы-корреспондента, с которой выполняется настройка обмена (см. параметры).
// Выполняется поиск записи по имени предопределенного или по адресу или создание новой записи (если не найдена).
// Настройки почты этой базы приводятся в соответствие с настройкой почты корреспондента.
//
// Параметры:
//   УчетнаяЗаписьКорреспондента - СправочникОбъект.УчетныеЗаписиЭлектроннойПочты - настройки электронной почты
//                   базы-корреспондента, полученная из файла настройки синхронизации данных путем
//                   десериализации с помощью метода ПрочитатьXML.
//
// Возвращаемое значение:
//  СправочникОбъект.УчетныеЗаписиЭлектроннойПочты
//
Функция УчетнаяЗаписьЭтойБазыПоДаннымУчетнойЗаписиКорреспондента(УчетнаяЗаписьКорреспондента) Экспорт
	
	НачатьТранзакцию();
	Попытка
		Блокировка = Новый БлокировкаДанных;
		Блокировка.Добавить("Справочник.УчетныеЗаписиЭлектроннойПочты");
		Блокировка.Заблокировать();
		
		УчетнаяЗаписьЭтойБазы = Неопределено;
		// Для предопределенной записи - перезаписываем предопределенный элемент текущей ИБ.
		Если УчетнаяЗаписьКорреспондента.Предопределенный Тогда
			УчетнаяЗаписьЭтойБазы = Справочники.УчетныеЗаписиЭлектроннойПочты[УчетнаяЗаписьКорреспондента.ИмяПредопределенныхДанных].ПолучитьОбъект();
		Иначе
			// Для обычной записи ищем существующую запись с тем же адресом.
			Запрос = Новый Запрос;
			Запрос.Текст = "ВЫБРАТЬ ПЕРВЫЕ 1
			|	Ссылка
			|ИЗ Справочник.УчетныеЗаписиЭлектроннойПочты
			|ГДЕ АдресЭлектроннойПочты = &АдресЭлектроннойПочты";
			Запрос.УстановитьПараметр("АдресЭлектроннойПочты", УчетнаяЗаписьКорреспондента.АдресЭлектроннойПочты);
			Выборка = Запрос.Выполнить().Выбрать();
			Если Выборка.Следующий() Тогда
				УчетнаяЗаписьЭтойБазы = Выборка.Ссылка.ПолучитьОбъект();
			КонецЕсли;
		КонецЕсли;
		
		Если УчетнаяЗаписьЭтойБазы <> Неопределено Тогда
			ЗаполнитьЗначенияСвойств(УчетнаяЗаписьЭтойБазы, УчетнаяЗаписьКорреспондента,, "ИмяПредопределенныхДанных, Родитель, Владелец, Ссылка");
		Иначе
			УчетнаяЗаписьЭтойБазы = УчетнаяЗаписьКорреспондента;
		КонецЕсли;
		
		УчетнаяЗаписьЭтойБазы.Записать();
	
		ЗафиксироватьТранзакцию();
	Исключение
		ОтменитьТранзакцию();
		ВызватьИсключение;
	КонецПопытки;
	
	Возврат УчетнаяЗаписьЭтойБазы;
	
КонецФункции

// Возвращает тип текстов электронных писем по наименованию.
//
Функция ТипТекстовЭлектронныхПисем(Наименование) Экспорт
	
	Возврат Перечисления.ТипыТекстовЭлектронныхПисем[Наименование];
	
КонецФункции

// Определяет, предусмотрено ли в программе получение писем.
// 
// Возвращаемое значение:
//  Булево
//
Функция ДоступноПолучениеПисем() Экспорт
	
	Возврат НастройкиПодсистемы().ДоступноПолучениеПисем;
	
КонецФункции

// Возвращает настройки подключения к почтовому серверу для отправки почты.
// Если настройки почты не существуют или не доступны по правам, то будет возвращена пустая структура.
//
// Параметры:
//  УчетнаяЗапись - СправочникСсылка.УчетныеЗаписиЭлектроннойПочты - настройка почты.
//
// Возвращаемое значение:
//  Структура:
//   * АдресСервераSMTP - Строка
//   * ПортSMTP - Число - порт STMP, по умолчанию 25.
//   * ПарольSMTP - Строка - пароля для сервера STMP
//   * ИспользоватьSSL - Булево - по умолчанию Ложь.
//   * ПользовательSMTP - Строка
//   * ИмяОтправителя - Строка
//
Функция НастройкиУчетнойЗаписиДляОтправкиПочта(УчетнаяЗапись) Экспорт
	
	Результат = Новый Структура;
	Результат.Вставить("АдресСервераSMTP", "");
	Результат.Вставить("ПортSMTP",         25);
	Результат.Вставить("ПарольSMTP",       "");
	Результат.Вставить("ИспользоватьSSL",  Ложь);
	Результат.Вставить("ПользовательSMTP", "");
	Результат.Вставить("ИмяОтправителя",   "");
	
	ТекстЗапроса =
		"ВЫБРАТЬ РАЗРЕШЕННЫЕ
		|	УчетныеЗаписиЭлектроннойПочты.СерверИсходящейПочты КАК АдресСервераSMTP,
		|	УчетныеЗаписиЭлектроннойПочты.ПортСервераИсходящейПочты КАК ПортSMTP,
		|	УчетныеЗаписиЭлектроннойПочты.ИспользоватьЗащищенноеСоединениеДляИсходящейПочты КАК ИспользоватьSSL,
		|	УчетныеЗаписиЭлектроннойПочты.Пользователь КАК ПользовательSMTP,
		|	УчетныеЗаписиЭлектроннойПочты.ИмяПользователя КАК ИмяОтправителя
		|ИЗ
		|	Справочник.УчетныеЗаписиЭлектроннойПочты КАК УчетныеЗаписиЭлектроннойПочты
		|ГДЕ
		|	УчетныеЗаписиЭлектроннойПочты.Ссылка = &Ссылка";
	
	Запрос = Новый Запрос(ТекстЗапроса);
	Запрос.УстановитьПараметр("Ссылка", УчетнаяЗапись);
	РезультатЗапроса = Запрос.Выполнить();
	
	Если РезультатЗапроса.Пустой() Тогда
		Возврат Результат;
	КонецЕсли;
	
	Выборка = РезультатЗапроса.Выбрать();
	
	Если Выборка.Следующий() Тогда
		
		УстановитьПривилегированныйРежим(Истина);
		ПарольSMTP = ОбщегоНазначения.ПрочитатьДанныеИзБезопасногоХранилища(УчетнаяЗапись, "ПарольSMTP");
		УстановитьПривилегированныйРежим(Ложь);
		
		ЗаполнитьЗначенияСвойств(Результат, Выборка);
		Результат.ПарольSMTP = ПарольSMTP;
		
	КонецЕсли;
	
	Возврат Результат;
	
КонецФункции

Функция ВажностьИнтернетПочтовогоСообщенияИзСтроки(Важность) Экспорт
	
	Если СтрСравнить(Важность, РаботаСПочтовымиСообщениямиСлужебныйКлиентСервер.ВысокаяВажностьИнтернетПочтовогоСообщения()) = 0 Тогда
		Возврат ВажностьИнтернетПочтовогоСообщения.Высокая;
	ИначеЕсли СтрСравнить(Важность, РаботаСПочтовымиСообщениямиСлужебныйКлиентСервер.НизкаяВажностьИнтернетПочтовогоСообщения()) = 0 Тогда
		Возврат ВажностьИнтернетПочтовогоСообщения.Низкая;
	Иначе
		Возврат ВажностьИнтернетПочтовогоСообщения.Обычная;
	КонецЕсли;
	
КонецФункции 

// Восстановление пароля

Процедура ОбновитьНастройкиСервераВосстановленияПочты(Ссылка) Экспорт
	
	Если Не Пользователи.ЭтоПолноправныйПользователь() Тогда
		Возврат;
	КонецЕсли;
	
	НастройкиУчетнойЗаписи = НастройкиУчетнойЗаписиДляВосстановленияПароля();
	Если Не НастройкиУчетнойЗаписи.Используется
		Или НастройкиУчетнойЗаписи.УчетнаяЗаписьПочты <> Ссылка Тогда
			Возврат;
	КонецЕсли;
	
	НастройкиВосстановленияПароля = ДополнительныеНастройкиАутентификации.ПолучитьНастройкиВосстановленияПароля();
	
	Если НастройкиВосстановленияПароля.СпособВосстановленияПароля
			<> СпособВосстановленияПароляПользователяИнформационнойБазы.ОтправкаКодаПодтвержденияПоЗаданнымПараметрам Тогда
		Возврат;
	КонецЕсли;
	
	НастройкиУчетнойЗаписиДляОтправкиПочта = НастройкиУчетнойЗаписиДляОтправкиПочта(Ссылка);
	ЗаполнитьЗначенияСвойств(НастройкиВосстановленияПароля, НастройкиУчетнойЗаписиДляОтправкиПочта);
	
	ДополнительныеНастройкиАутентификации.УстановитьНастройкиВосстановленияПароля(НастройкиВосстановленияПароля);
	
КонецПроцедуры

Процедура СохранитьНастройкиУчетнойЗаписиДляВосстановленияПароля(Настройки) Экспорт
	
	Если ТипЗнч(Настройки) <> Тип("Структура") Тогда
		ВызватьИсключение НСтр("ru='Неверный тип настроек почты для восстановления пароля.'");
	КонецЕсли;
	
	СведенияОбУчетнойЗаписи = ОписаниеНастроекУчетнойЗаписиДляВосстановленияПароля();
	ЗаполнитьЗначенияСвойств(СведенияОбУчетнойЗаписи, Настройки);
	
	Константы.УчетнаяЗаписьДляВосстановленияПароля.Установить(Новый ХранилищеЗначения(СведенияОбУчетнойЗаписи));
	
КонецПроцедуры

Функция НастройкиУчетнойЗаписиДляВосстановленияПароля() Экспорт
	
	СведенияОбУчетнойЗаписи = ОписаниеНастроекУчетнойЗаписиДляВосстановленияПароля();
	
	УстановитьПривилегированныйРежим(Истина);
	ДанныеИзКонстанты = Константы.УчетнаяЗаписьДляВосстановленияПароля.Получить();
	Если ТипЗнч(ДанныеИзКонстанты) = Тип("ХранилищеЗначения") Тогда
		
		СведенияОбУчетнойЗаписиДляВосстановленияПароля = ДанныеИзКонстанты.Получить();
		Если ТипЗнч(СведенияОбУчетнойЗаписиДляВосстановленияПароля) = Тип("Структура") Тогда
			ЗаполнитьЗначенияСвойств(СведенияОбУчетнойЗаписи, СведенияОбУчетнойЗаписиДляВосстановленияПароля);
		КонецЕсли;
		
	КонецЕсли;
	
	Возврат СведенияОбУчетнойЗаписи;

КонецФункции

Функция ОписаниеНастроекУчетнойЗаписиДляВосстановленияПароля() Экспорт
	
	СведенияОбУчетнойЗаписи = Новый Структура();
	СведенияОбУчетнойЗаписи.Вставить("УчетнаяЗаписьПочты", Неопределено);
	СведенияОбУчетнойЗаписи.Вставить("Используется",       Ложь);
	
	Возврат СведенияОбУчетнойЗаписи;
	
КонецФункции

////////////////////////////////////////////////////////////////////////////////
// Обработчики событий подсистем конфигурации.

// См. ГрупповоеИзменениеОбъектовПереопределяемый.ПриОпределенииОбъектовСРедактируемымиРеквизитами.
Процедура ПриОпределенииОбъектовСРедактируемымиРеквизитами(Объекты) Экспорт
	Объекты.Вставить(Метаданные.Справочники.УчетныеЗаписиЭлектроннойПочты.ПолноеИмя(), "РеквизитыРедактируемыеВГрупповойОбработке");
КонецПроцедуры

// См. РаботаВБезопасномРежимеПереопределяемый.ПриЗаполненииРазрешенийНаДоступКВнешнимРесурсам.
Процедура ПриЗаполненииРазрешенийНаДоступКВнешнимРесурсам(ЗапросыРазрешений) Экспорт

	Если ОбщегоНазначения.РазделениеВключено()
	   И Не ОбщегоНазначения.ДоступноИспользованиеРазделенныхДанных() Тогда
		Возврат;
	КонецЕсли;
	
	МодульРаботаВБезопасномРежиме = ОбщегоНазначения.ОбщийМодуль("РаботаВБезопасномРежиме");
	
	РазрешенияУчетныхЗаписей = Справочники.УчетныеЗаписиЭлектроннойПочты.РазрешенияУчетныхЗаписей();
	Для Каждого ОписаниеРазрешений Из РазрешенияУчетныхЗаписей Цикл
		ЗапросыРазрешений.Добавить(МодульРаботаВБезопасномРежиме.ЗапросНаИспользованиеВнешнихРесурсов(
			ОписаниеРазрешений.Значение, ОписаниеРазрешений.Ключ));
	КонецЦикла;
	
	ЗапросыРазрешений.Добавить(
		МодульРаботаВБезопасномРежиме.ЗапросНаИспользованиеВнешнихРесурсов(Разрешения()));
		
	Справочники.НастройкиАвторизацииИнтернетСервисов.ПриЗаполненииРазрешенийНаДоступКВнешнимРесурсам(ЗапросыРазрешений);
	
КонецПроцедуры

// См. СтандартныеПодсистемыСервер.ПриПолученииДанныхОтГлавного.
Процедура ПриПолученииДанныхОтГлавного(ЭлементДанных, ПолучениеЭлемента, ОтправкаНазад, Отправитель) Экспорт
	
	ПриПолученииДанных(ЭлементДанных, ПолучениеЭлемента, ОтправкаНазад, Отправитель);
	
КонецПроцедуры

// См. СтандартныеПодсистемыСервер.ПриПолученииДанныхОтПодчиненного.
Процедура ПриПолученииДанныхОтПодчиненного(ЭлементДанных, ПолучениеЭлемента, ОтправкаНазад, Отправитель) Экспорт
	
	ПриПолученииДанных(ЭлементДанных, ПолучениеЭлемента, ОтправкаНазад, Отправитель);
	
КонецПроцедуры

// См. ОбменДаннымиПереопределяемый.ПриНастройкеПодчиненногоУзлаРИБ.
Процедура ПриНастройкеПодчиненногоУзлаРИБ() Экспорт
	
	ОтключитьИспользованиеУчетныхЗаписей();
	
КонецПроцедуры

// См. ОбновлениеИнформационнойБазыБСП.ПриДобавленииОбработчиковОбновления.
Процедура ПриДобавленииОбработчиковОбновления(Обработчики) Экспорт
	
	Обработчик = Обработчики.Добавить();
	Обработчик.Версия = "3.1.3.40";
	Обработчик.Процедура = "Справочники.УчетныеЗаписиЭлектроннойПочты.ОбработатьДанныеДляПереходаНаНовуюВерсию";
	Обработчик.РежимВыполнения = "Отложенно";
	Обработчик.Идентификатор = Новый УникальныйИдентификатор("d57f7a36-46ca-4a52-baab-db960e3d376d");
	Обработчик.Комментарий = НСтр("ru = 'Обновляет сведения об учетных записях электронной почты.
		|До завершения обработки список учетных записей электронной почты может быть неполным.'");
	Обработчик.ПроцедураЗаполненияДанныхОбновления = "Справочники.УчетныеЗаписиЭлектроннойПочты.ЗарегистрироватьДанныеКОбработкеДляПереходаНаНовуюВерсию";
	
	ЧитаемыеОбъекты = Новый Массив;
	ЧитаемыеОбъекты.Добавить("Справочник.УчетныеЗаписиЭлектроннойПочты");
	
	ИзменяемыеОбъекты = Новый Массив;
	ИзменяемыеОбъекты.Добавить("Справочник.УчетныеЗаписиЭлектроннойПочты");

	Если ОбщегоНазначения.ПодсистемаСуществует("СтандартныеПодсистемы.Взаимодействия") Тогда
		МодульВзаимодействия = ОбщегоНазначения.ОбщийМодуль("Взаимодействия");
		МодульВзаимодействия.ПриПолученииЧитаемыхОбъектовОбработчикаОбновленияУчетныхЗаписейЭлектроннойПочты(ЧитаемыеОбъекты);
		МодульВзаимодействия.ПриПолученииИзменяемыхОбъектовОбработчикаОбновленияУчетныхЗаписейЭлектроннойПочты(ИзменяемыеОбъекты);
	КонецЕсли;
		
	Обработчик.ЧитаемыеОбъекты = СтрСоединить(ЧитаемыеОбъекты, ",");
	Обработчик.ИзменяемыеОбъекты = СтрСоединить(ИзменяемыеОбъекты, ",");
	
	Если ОбщегоНазначения.ПодсистемаСуществует("СтандартныеПодсистемы.Мультиязычность") Тогда
		Обработчик.ПриоритетыВыполнения = ОбновлениеИнформационнойБазы.ПриоритетыВыполненияОбработчика();
		НоваяСтрока = Обработчик.ПриоритетыВыполнения.Добавить();
		НоваяСтрока.Процедура = "МультиязычностьСервер.ОбработатьДанныеДляПереходаНаНовуюВерсию";
		НоваяСтрока.Порядок = "До";
	КонецЕсли;
	
КонецПроцедуры

// См. УправлениеДоступомПереопределяемый.ПриЗаполненииВидовДоступа.
Процедура ПриЗаполненииВидовДоступа(ВидыДоступа) Экспорт
	
	ВидДоступа = ВидыДоступа.Добавить();
	ВидДоступа.Имя = "УчетныеЗаписиЭлектроннойПочты";
	ВидДоступа.Представление = НСтр("ru = 'Учетные записи электронной почты'");
	ВидДоступа.ТипЗначений   = Тип("СправочникСсылка.УчетныеЗаписиЭлектроннойПочты");
	
КонецПроцедуры

// См. УправлениеДоступомПереопределяемый.ПриЗаполненииСписковСОграничениемДоступа.
Процедура ПриЗаполненииСписковСОграничениемДоступа(Списки) Экспорт
	
	Списки.Вставить(Метаданные.Справочники.УчетныеЗаписиЭлектроннойПочты, Истина);
	
КонецПроцедуры

// См. УправлениеДоступомПереопределяемый.ПриЗаполненииВидовОграниченийПравОбъектовМетаданных.
Процедура ПриЗаполненииВидовОграниченийПравОбъектовМетаданных(Описание) Экспорт
	
	Если НЕ ОбщегоНазначения.ПодсистемаСуществует("СтандартныеПодсистемы.УправлениеДоступом") Тогда
		Возврат;
	КонецЕсли;
	
	МодульУправлениеДоступомСлужебный = ОбщегоНазначения.ОбщийМодуль("УправлениеДоступомСлужебный");
	
	Если МодульУправлениеДоступомСлужебный.ВидДоступаСуществует("УчетныеЗаписиЭлектроннойПочты") Тогда
		
		Описание = Описание + "
		|Справочник.УчетныеЗаписиЭлектроннойПочты.Чтение.УчетныеЗаписиЭлектроннойПочты
		|Справочник.УчетныеЗаписиЭлектроннойПочты.Чтение.Пользователи
		|Справочник.УчетныеЗаписиЭлектроннойПочты.Изменение.Пользователи
		|";
		
	КонецЕсли;
	
КонецПроцедуры

// См. ОбщегоНазначенияПереопределяемый.ПриДобавленииПереименованийОбъектовМетаданных.
Процедура ПриДобавленииПереименованийОбъектовМетаданных(Итог) Экспорт
	
	Библиотека = "СтандартныеПодсистемы";
	
	СтароеИмя = "Роль.ИспользованиеУчетныхЗаписейЭлектроннойПочты";
	НовоеИмя  = "Роль.ЧтениеУчетныхЗаписейЭлектроннойПочты";
	ОбщегоНазначения.ДобавитьПереименование(Итог, "2.3.3.11", СтароеИмя, НовоеИмя, Библиотека);
	
	СтароеИмя = "Роль.ЧтениеУчетныхЗаписейЭлектроннойПочты";
	НовоеИмя  = "Роль.ДобавлениеИзменениеУчетныхЗаписейЭлектроннойПочты";
	ОбщегоНазначения.ДобавитьПереименование(Итог, "2.4.1.1", СтароеИмя, НовоеИмя, Библиотека);
	
КонецПроцедуры

// Смотри также ОбновлениеИнформационнойБазыПереопределяемый.ПриОпределенииНастроек
//
// Параметры:
//  Объекты - Массив из ОбъектМетаданных
//
Процедура ПриОпределенииОбъектовСНачальнымЗаполнением(Объекты) Экспорт
	
	Объекты.Добавить(Метаданные.Справочники.УчетныеЗаписиЭлектроннойПочты);
	
КонецПроцедуры

// См. ОчередьЗаданийПереопределяемый.ПриОпределенииПсевдонимовОбработчиков.
Процедура ПриОпределенииПсевдонимовОбработчиков(СоответствиеИменПсевдонимам) Экспорт
	
	СоответствиеИменПсевдонимам.Вставить(Метаданные.РегламентныеЗадания.ПолучениеСтатусовЭлектронныхПисем.ИмяМетода);   	
	
КонецПроцедуры

// Кодирует строку по алгоритму Punycode
// 
// Параметры:
//  Строка - Строка - исходная строка
// 
// Возвращаемое значение:
//  Строка - кодированная строка
//
Функция СтрокаВPunycode(Знач Строка) Экспорт

	СтруктураURI = ОбщегоНазначенияКлиентСервер.СтруктураURI(Строка);
	АдресХоста = СтруктураURI.Хост;
	КодированныйАдресХоста = КодироватьСтрокуСРазделителем(АдресХоста);
	Результат = СтрЗаменить(Строка, АдресХоста, КодированныйАдресХоста);
	
	Логин = СтруктураURI.Логин;
	КодированныйЛогин = КодироватьСтрокуСРазделителем(Логин);
	Результат = СтрЗаменить(Результат, Логин, КодированныйЛогин);
		
	Возврат Результат;
КонецФункции

// Декодирует адреса электронной почты по алгоритму Punycode
// 
// Параметры:
//  Письмо - ИнтернетПочтовоеСообщение - обрабатываемое письмо
//
Процедура ДекодироватьАдресаВПисьме(Письмо) Экспорт
	ДекодироватьКоллекциюАдресов(Письмо.АдресаУведомленияОПрочтении);
	ДекодироватьКоллекциюАдресов(Письмо.ОбратныйАдрес);
	ДекодироватьКоллекциюАдресов(Письмо.Получатели);
	ДекодироватьКоллекциюАдресов(Письмо.СлепыеКопии);
	Письмо.Отправитель.Адрес = PunycodeВСтроку(Письмо.Отправитель.Адрес);
КонецПроцедуры

#КонецОбласти

#Область СлужебныеПроцедурыИФункции

// Проверяет, что предопределенная системная учетная запись электронной почты
// доступна для использования.
//
Функция ПроверитьСистемнаяУчетнаяЗаписьДоступна() Экспорт
	
	Если НЕ ПравоДоступа("Чтение", Метаданные.Справочники.УчетныеЗаписиЭлектроннойПочты) Тогда
		Возврат Ложь;
	КонецЕсли;
	
	ТекстЗапроса =
		"ВЫБРАТЬ РАЗРЕШЕННЫЕ
		|	УчетныеЗаписиЭлектроннойПочты.Ссылка КАК Ссылка
		|ИЗ
		|	Справочник.УчетныеЗаписиЭлектроннойПочты КАК УчетныеЗаписиЭлектроннойПочты
		|ГДЕ
		|	УчетныеЗаписиЭлектроннойПочты.Ссылка = &Ссылка";
	
	Запрос = Новый Запрос;
	Запрос.Текст = ТекстЗапроса;
	Запрос.Параметры.Вставить("Ссылка", РаботаСПочтовымиСообщениями.СистемнаяУчетнаяЗапись());
	Если Запрос.Выполнить().Пустой() Тогда
		Возврат Ложь;
	КонецЕсли;
	
	Возврат Истина;
	
КонецФункции

Процедура ОтправитьСообщение(Знач УчетнаяЗапись, Знач ПараметрыОтправки) Экспорт
	Перем ПротоколПочты, Соединение;
	
	Письмо = ПодготовитьПисьмо(УчетнаяЗапись, ПараметрыОтправки);
	РеквизитыОтправителя = ОбщегоНазначения.ЗначенияРеквизитовОбъекта(УчетнаяЗапись, "ИмяПользователя,АдресЭлектроннойПочты,ОтправлятьСкрытыеКопииПисемНаЭтотАдрес");
	
	ПараметрыОтправки.Свойство("Соединение", Соединение);
	ПараметрыОтправки.Свойство("ПротоколПочты", ПротоколПочты);
	
	ПараметрыОтправки.Вставить("ИдентификаторСообщения", "");
	ПараметрыОтправки.Вставить("ИдентификаторСообщенияОтправкаIMAP", "");
	ПараметрыОтправки.Вставить("ОшибочныеПолучатели", Новый Соответствие);
	
	СоздаватьСоединение = ТипЗнч(Соединение) <> Тип("ИнтернетПочта");
	
	Если СоздаватьСоединение Тогда
		РезультатОтправки = ОтправитьПисьмо(УчетнаяЗапись, Письмо);
		ПараметрыОтправки.ОшибочныеПолучатели = РезультатОтправки.ОшибочныеПолучатели;
		ПараметрыОтправки.ИдентификаторСообщения = РезультатОтправки.ИдентификаторПисьмаSMTP;
		ПараметрыОтправки.ИдентификаторСообщенияОтправкаIMAP = РезультатОтправки.ИдентификаторПисьмаIMAP;
		Возврат;
	КонецЕсли;
	
	Если РеквизитыОтправителя.ОтправлятьСкрытыеКопииПисемНаЭтотАдрес Тогда
		Получатель = Письмо.СлепыеКопии.Добавить(РеквизитыОтправителя.АдресЭлектроннойПочты);
		Получатель.ОтображаемоеИмя = РеквизитыОтправителя.ИмяПользователя;
	КонецЕсли;
	
	УстановитьОтключениеБезопасногоРежима(Истина);
	Профиль = ИнтернетПочтовыйПрофиль(УчетнаяЗапись);
	УстановитьОтключениеБезопасногоРежима(Ложь);
	
	Если ПротоколПочты = "IMAP" Или ПротоколПочты = "Все" И Не ПочтовыйСерверХранитПисьмаОтправленныеПоSMTP(Профиль) Тогда
		Соединение.Послать(Письмо, ОбработкаТекстаИнтернетПочтовогоСообщения.НеОбрабатывать, ПротоколИнтернетПочты.IMAP);
		ПараметрыОтправки.ИдентификаторСообщенияОтправкаIMAP = Письмо.ИдентификаторСообщения;
		
		ФлагиПисьма = Новый ФлагиИнтернетПочтовогоСообщения;
		ФлагиПисьма.Прочитанное = Истина;
		ФлагиПисем = Новый Соответствие;
		ФлагиПисем.Вставить(Письмо.ИдентификаторСообщения, ФлагиПисьма);
		Соединение.УстановитьФлагиСообщений(ФлагиПисем);
	КонецЕсли;
	
	Если Не ЗначениеЗаполнено(ПротоколПочты) Или ПротоколПочты = "Все" Тогда 
		ОшибочныеПолучатели = Соединение.Послать(Письмо, ОбработкаТекстаИнтернетПочтовогоСообщения.НеОбрабатывать,
			ПротоколИнтернетПочты.SMTP);
			
		ПараметрыОтправки.ИдентификаторСообщения = Письмо.ИдентификаторСообщения;
		ПараметрыОтправки.ОшибочныеПолучатели = ОшибочныеПолучатели;
	КонецЕсли;
	
КонецПроцедуры

Процедура ОпределитьПапкуОтправленные(Соединение)
	
	ПочтовыеЯщики = Соединение.ПолучитьПочтовыеЯщики();
	Для Каждого ПочтовыйЯщик Из ПочтовыеЯщики Цикл
		Если НРег(ПочтовыйЯщик) = "отправленные"
			Или НРег(ПочтовыйЯщик) = "inbox.sent"
			Или НРег(ПочтовыйЯщик) = "sent"
			Или НРег(ПочтовыйЯщик) = "sent items" Тогда
			
			Соединение.ТекущийПочтовыйЯщик = ПочтовыйЯщик;
			Прервать;
			
		КонецЕсли;
	КонецЦикла;
	
КонецПроцедуры

Функция ИспользоватьIMAPПриОтправкеПисем(Профиль)
	
	Возврат Не ПочтовыйСерверХранитПисьмаОтправленныеПоSMTP(Профиль)
		И ЗначениеЗаполнено(Профиль.АдресСервераIMAP)
		И ЗначениеЗаполнено(Профиль.ПортIMAP)
		И ЗначениеЗаполнено(Профиль.ПользовательIMAP)
		И Профиль.ПарольIMAP <> "";
	
КонецФункции

// Параметры:
//  УчетнаяЗапись - см. РаботаСПочтовымиСообщениями.ЗагрузитьПочтовыеСообщения.УчетнаяЗапись
//  ПараметрыЗагрузки - см. РаботаСПочтовымиСообщениями.ЗагрузитьПочтовыеСообщения.ПараметрыЗагрузки
//
// Возвращаемое значение:
//   см. РаботаСПочтовымиСообщениями.ЗагрузитьПочтовыеСообщения
//
Функция ЗагрузитьСообщения(Знач УчетнаяЗапись, Знач ПараметрыЗагрузки = Неопределено) Экспорт
	
	// Используется для проверки возможности входа на почтовый ящик.
	Перем РежимТестирования;
	
	// Получать только заголовки писем.
	Перем ПолучениеЗаголовков;
	
	// Приводить почтовые сообщения к простому типу;
	Перем ПриводитьСообщенияКТипу;
	
	// Заголовки или идентификаторы писем, полные сообщения по которым требуется получить.
	Перем ЗаголовкиИдентификаторы;
	
	Если ПараметрыЗагрузки.Свойство("РежимТестирования") Тогда
		РежимТестирования = ПараметрыЗагрузки.РежимТестирования;
	Иначе
		РежимТестирования = Ложь;
	КонецЕсли;
	
	Если ПараметрыЗагрузки.Свойство("ПолучениеЗаголовков") Тогда
		ПолучениеЗаголовков = ПараметрыЗагрузки.ПолучениеЗаголовков;
	Иначе
		ПолучениеЗаголовков = Ложь;
	КонецЕсли;
	
	УстановитьОтключениеБезопасногоРежима(Истина);
	Профиль = ИнтернетПочтовыйПрофиль(УчетнаяЗапись, Истина);
	УстановитьОтключениеБезопасногоРежима(Ложь);
	
	Если ПараметрыЗагрузки.Свойство("ЗаголовкиИдентификаторы") Тогда
		ЗаголовкиИдентификаторы = ПараметрыЗагрузки.ЗаголовкиИдентификаторы;
	Иначе
		ЗаголовкиИдентификаторы = Новый Массив;
	КонецЕсли;
	
	Если ПараметрыЗагрузки.Свойство("Отбор") Тогда
		Отбор = ПараметрыЗагрузки.Отбор;
	Иначе
		Отбор = Новый Структура;
	КонецЕсли;
	
	НаборСообщенийДляУдаления = Новый Массив;
	
	Протокол = ПротоколИнтернетПочты.POP3;
	НастройкиТранспорта = ОбщегоНазначения.ЗначенияРеквизитовОбъекта(УчетнаяЗапись, "ПротоколВходящейПочты,ОставлятьКопииСообщенийНаСервере,ПериодХраненияСообщенийНаСервере");
	Если НастройкиТранспорта.ПротоколВходящейПочты = "IMAP" Тогда
		НастройкиТранспорта.ОставлятьКопииСообщенийНаСервере = Истина;
		НастройкиТранспорта.ПериодХраненияСообщенийНаСервере = 0;
		Протокол = ПротоколИнтернетПочты.IMAP;
	КонецЕсли;
	
	УстановитьОтключениеБезопасногоРежима(Истина);
	Соединение = Новый ИнтернетПочта;
	Соединение.Подключиться(Профиль, Протокол);
	
	Если РежимТестирования Тогда	
		Соединение.Отключиться();
		Возврат Истина;
	КонецЕсли;
	
	Попытка
		Если ПолучениеЗаголовков Или ЗаголовкиИдентификаторы.Количество() = 0 Тогда
			ЗаголовкиИдентификаторы = Соединение.ПолучитьЗаголовки(Отбор);
			НаборПисем = ЗаголовкиИдентификаторы;
		КонецЕсли;
		
		Если Не ПолучениеЗаголовков И Не (ЗначениеЗаполнено(Отбор) И ЗаголовкиИдентификаторы.Количество() = 0) Тогда
			Если НастройкиТранспорта.ОставлятьКопииСообщенийНаСервере Тогда
				Если НастройкиТранспорта.ПериодХраненияСообщенийНаСервере > 0 Тогда
					НаборСообщенийДляУдаления = Новый Массив;
					Для Каждого ЭлементЗаголовок Из ЗаголовкиИдентификаторы Цикл
						ТекущаяДата = ТекущаяДатаСеанса();
						РазницаДат = (ТекущаяДата - ЭлементЗаголовок.ДатаОтправления) / (3600*24);
						Если РазницаДат >= НастройкиТранспорта.ПериодХраненияСообщенийНаСервере Тогда
							НаборСообщенийДляУдаления.Добавить(ЭлементЗаголовок);
						КонецЕсли;
					КонецЦикла;
				КонецЕсли;
				АвтоматическиУдалятьСообщенияПриВыбореССервера = Ложь;
			Иначе
				АвтоматическиУдалятьСообщенияПриВыбореССервера = Истина;
			КонецЕсли;
			
			НаборПисем = Соединение.Выбрать(АвтоматическиУдалятьСообщенияПриВыбореССервера, ЗаголовкиИдентификаторы);
			
			Если НаборСообщенийДляУдаления.Количество() > 0 Тогда
				Соединение.УдалитьСообщения(НаборСообщенийДляУдаления);
			КонецЕсли;
		КонецЕсли;
	
		Соединение.Отключиться();
	Исключение
		Попытка
			Соединение.Отключиться();
		Исключение // АПК:280
			// Обработка и журналирование исключения не требуется, т.к. 
			// в вызывающий код передается исходное исключение, которое будет там обработано.
		КонецПопытки;
		ВызватьИсключение;
	КонецПопытки;
	УстановитьОтключениеБезопасногоРежима(Ложь);
	
	Если РежимТестирования Тогда
		Возврат Истина;
	КонецЕсли;
	
	Если ПараметрыЗагрузки.Свойство("ПриводитьСообщенияКТипу") Тогда
		ПриводитьСообщенияКТипу = ПараметрыЗагрузки.ПриводитьСообщенияКТипу;
	Иначе
		ПриводитьСообщенияКТипу = Истина;
	КонецЕсли;

	Колонки = Неопределено;
	Если ПараметрыЗагрузки.Свойство("Колонки") Тогда
		Колонки = ПараметрыЗагрузки.Колонки;
	КонецЕсли;
	
	Если ПриводитьСообщенияКТипу Тогда
		Возврат АдаптированныйНаборПисем(НаборПисем, Колонки);
	КонецЕсли;
	
	Возврат НаборПисем;
	
КонецФункции

// Преобразует набор почтовых сообщений в таблицу значений с колонками простых типов.
// Значения колонок, типы которых не поддерживаются на клиенте, преобразуются к строковому виду.
//
Функция АдаптированныйНаборПисем(Знач НаборПисем, Знач Колонки = Неопределено)
	
	Результат = СоздатьАдаптированноеОписаниеПисьма(Колонки);
	
	Для Каждого ПочтовоеСообщение Из НаборПисем Цикл
		НоваяСтрока = Результат.Добавить();
		Для Каждого НаименованиеКолонки Из Колонки Цикл
			ПолеПисьма = ПочтовоеСообщение[НаименованиеКолонки];
			
			Если ТипЗнч(ПолеПисьма) = Тип("Строка") Тогда
				ПолеПисьма = ОбщегоНазначенияКлиентСервер.УдалитьНедопустимыеСимволыXML(ПолеПисьма);
			ИначеЕсли ТипЗнч(ПолеПисьма) = Тип("ИнтернетПочтовыеАдреса") Тогда
				ПолеПисьма = ПредставлениеАдресов(ПолеПисьма);
			ИначеЕсли ТипЗнч(ПолеПисьма) = Тип("ИнтернетПочтовыйАдрес") Тогда
				ПолеПисьма = ПредставлениеАдреса(ПолеПисьма);
			ИначеЕсли ТипЗнч(ПолеПисьма) = Тип("ИнтернетПочтовыеВложения") Тогда
				Вложения = Новый Соответствие;
				Для Каждого Вложение Из ПолеПисьма Цикл
					Если ТипЗнч(Вложение.Данные) = Тип("ДвоичныеДанные") Тогда
						Вложения.Вставить(Вложение.Имя, Вложение.Данные);
					Иначе
						ЗаполнитьВложенияПоПисьму(Вложения, Вложение.Данные);
					КонецЕсли;
				КонецЦикла;
				ПолеПисьма = Вложения;
			ИначеЕсли ТипЗнч(ПолеПисьма) = Тип("ИнтернетТекстыПочтовогоСообщения") Тогда
				Тексты = Новый Массив;
				Для Каждого ОчереднойТекст Из ПолеПисьма Цикл
					ОписаниеТекста = Новый Соответствие;
					ОписаниеТекста.Вставить("Данные", ОчереднойТекст.Данные);
					ОписаниеТекста.Вставить("Кодировка", ОчереднойТекст.Кодировка);
					ОписаниеТекста.Вставить("Текст", ОбщегоНазначенияКлиентСервер.УдалитьНедопустимыеСимволыXML(ОчереднойТекст.Текст));
					ОписаниеТекста.Вставить("ТипТекста", Строка(ОчереднойТекст.ТипТекста));
					Тексты.Добавить(ОписаниеТекста);
				КонецЦикла;
				ПолеПисьма = Тексты;
			ИначеЕсли ТипЗнч(ПолеПисьма) = Тип("ВажностьИнтернетПочтовогоСообщения")
				Или ТипЗнч(ПолеПисьма) = Тип("СпособКодированияНеASCIIСимволовИнтернетПочтовогоСообщения") Тогда
				ПолеПисьма = Строка(ПолеПисьма);
			КонецЕсли;
			
			НоваяСтрока[НаименованиеКолонки] = ПолеПисьма;
		КонецЦикла;
	КонецЦикла;
	
	Возврат Результат;
	
КонецФункции

Функция ПредставлениеАдреса(ИнтернетПочтовыйАдрес)
	Результат = PunycodeВСтроку(ИнтернетПочтовыйАдрес.Адрес);
	Если Не ПустаяСтрока(ИнтернетПочтовыйАдрес.ОтображаемоеИмя) Тогда
		Результат = ИнтернетПочтовыйАдрес.ОтображаемоеИмя + " <" + Результат + ">";
	КонецЕсли;
	Возврат Результат;
КонецФункции

Функция ПредставлениеАдресов(ИнтернетПочтовыеАдреса)
	Результат = "";
	Для Каждого ИнтернетПочтовыйАдрес Из ИнтернетПочтовыеАдреса Цикл
		Результат = ?(ПустаяСтрока(Результат), "", Результат + "; ") + ПредставлениеАдреса(ИнтернетПочтовыйАдрес);
	КонецЦикла;
	Возврат Результат;
КонецФункции

Процедура ЗаполнитьВложенияПоПисьму(Вложения, Письмо)
	
	Для Каждого Вложение Из Письмо.Вложения Цикл
		Если ТипЗнч(Вложение.Данные) = Тип("ДвоичныеДанные") Тогда
			Вложения.Вставить(Вложение.Имя, Вложение.Данные);
		Иначе
			ЗаполнитьВложенияПоПисьму(Вложения, Вложение.Данные);
		КонецЕсли;
	КонецЦикла;
	
	ПредставлениеПисьма = ПредставлениеПисьма(Письмо.Тема, Письмо.ДатаОтправления);
	
	Индекс = 0;
	Для Каждого Текст Из Письмо.Тексты Цикл
		Если Текст.ТипТекста = ТипТекстаПочтовогоСообщения.HTML Тогда
			Расширение = "html";
		ИначеЕсли Текст.ТипТекста = ТипТекстаПочтовогоСообщения.ПростойТекст Тогда
			Расширение = "txt";
		Иначе
			Расширение = "rtf";
		КонецЕсли;
		ИмяТекстаВложения = "";
		Пока ИмяТекстаВложения = "" Или Вложения.Получить(ИмяТекстаВложения) <> Неопределено Цикл
			Индекс = Индекс + 1;
			ИмяТекстаВложения = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку("%1 - (%2).%3", ПредставлениеПисьма, Индекс, Расширение);
		КонецЦикла;
		Вложения.Вставить(ИмяТекстаВложения, Текст.Данные);
	КонецЦикла;
	
КонецПроцедуры

// Функция подготавливает таблицу, в которой впоследствии будут
// храниться сообщения с почтового сервера.
// 
// Параметры:
//   Колонки - Строка - список полей письма, через запятую, которые должны
//                    быть записаны в таблицу. Параметр меняет тип на массив.
// Возвращаемое значение
//   ТаблицаЗначений - пустая таблица значений с колонками.
//
Функция СоздатьАдаптированноеОписаниеПисьма(Колонки = Неопределено)
	
	Если Колонки <> Неопределено
	   И ТипЗнч(Колонки) = Тип("Строка") Тогда
		Колонки = СтрРазделить(Колонки, ",");
		Для Индекс = 0 По Колонки.Количество()-1 Цикл
			Колонки[Индекс] = СокрЛП(Колонки[Индекс]);
		КонецЦикла;
	КонецЕсли;
	
	ПоляИнтернетПочтовогоСообщения = РаботаСПочтовымиСообщениями.ПоляИнтернетПочтовогоСообщения();
	
	МассивКолонокПоУмолчанию = Новый Массив;
	МассивКолонокПоУмолчанию.Добавить(ПоляИнтернетПочтовогоСообщения.Важность);
	МассивКолонокПоУмолчанию.Добавить(ПоляИнтернетПочтовогоСообщения.Вложения);
	МассивКолонокПоУмолчанию.Добавить(ПоляИнтернетПочтовогоСообщения.ДатаОтправления);
	МассивКолонокПоУмолчанию.Добавить(ПоляИнтернетПочтовогоСообщения.ДатаПолучения);
	МассивКолонокПоУмолчанию.Добавить(ПоляИнтернетПочтовогоСообщения.Заголовок);
	МассивКолонокПоУмолчанию.Добавить(ПоляИнтернетПочтовогоСообщения.ИмяОтправителя);
	МассивКолонокПоУмолчанию.Добавить(ПоляИнтернетПочтовогоСообщения.Идентификатор);
	МассивКолонокПоУмолчанию.Добавить(ПоляИнтернетПочтовогоСообщения.Копии);
	МассивКолонокПоУмолчанию.Добавить(ПоляИнтернетПочтовогоСообщения.ОбратныйАдрес);
	МассивКолонокПоУмолчанию.Добавить(ПоляИнтернетПочтовогоСообщения.Отправитель);
	МассивКолонокПоУмолчанию.Добавить(ПоляИнтернетПочтовогоСообщения.Получатели);
	МассивКолонокПоУмолчанию.Добавить(ПоляИнтернетПочтовогоСообщения.Размер);
	МассивКолонокПоУмолчанию.Добавить(ПоляИнтернетПочтовогоСообщения.Тема);
	МассивКолонокПоУмолчанию.Добавить(ПоляИнтернетПочтовогоСообщения.Тексты);
	МассивКолонокПоУмолчанию.Добавить(ПоляИнтернетПочтовогоСообщения.Кодировка);
	МассивКолонокПоУмолчанию.Добавить(ПоляИнтернетПочтовогоСообщения.СпособКодированияНеASCIIСимволов);
	МассивКолонокПоУмолчанию.Добавить(ПоляИнтернетПочтовогоСообщения.Частичное);
	
	Если Колонки = Неопределено Тогда
		Колонки = МассивКолонокПоУмолчанию;
	КонецЕсли;
	
	Результат = Новый ТаблицаЗначений;
	
	Для Каждого НаименованиеКолонки Из Колонки Цикл
		Результат.Колонки.Добавить(НаименованиеКолонки);
	КонецЦикла;
	
	Возврат Результат;
	
КонецФункции

Процедура ПроверитьВозможностьОтправкиИПолученияЭлектроннойПочты(УчетнаяЗапись, СообщениеОбОшибке, ДополнительноеСообщение) Экспорт
	
	НастройкиУчетнойЗаписи = ОбщегоНазначения.ЗначенияРеквизитовОбъекта(УчетнаяЗапись, "ИспользоватьДляОтправки,ИспользоватьДляПолучения,ПротоколВходящейПочты");
	
	СообщениеОбОшибке = "";
	ДополнительноеСообщение = "";
	
	Если НастройкиУчетнойЗаписи.ИспользоватьДляОтправки Тогда
		ТекстОшибки = Справочники.УчетныеЗаписиЭлектроннойПочты.ПроверитьВозможностьПодключенияКПочтовомуСерверу(УчетнаяЗапись, Ложь);
		Если ЗначениеЗаполнено(ТекстОшибки) Тогда
			СообщениеОбОшибке = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(НСтр("ru = 'Не удалось подключиться к серверу SMTP: %1'") + Символы.ПС, ТекстОшибки);
		КонецЕсли;
		Если Не НастройкиУчетнойЗаписи.ИспользоватьДляПолучения Тогда
			ДополнительноеСообщение = Символы.ПС + НСтр("ru = '(Выполнена проверка отправки электронных сообщений.)'");
		КонецЕсли;
	КонецЕсли;
	
	Если НастройкиУчетнойЗаписи.ИспользоватьДляПолучения 
		Или НастройкиУчетнойЗаписи.ИспользоватьДляОтправки И НастройкиУчетнойЗаписи.ПротоколВходящейПочты = "IMAP" Тогда
		
		ТекстОшибки = Справочники.УчетныеЗаписиЭлектроннойПочты.ПроверитьВозможностьПодключенияКПочтовомуСерверу(УчетнаяЗапись, Истина);
		Если ЗначениеЗаполнено(ТекстОшибки) Тогда
			Если ЗначениеЗаполнено(СообщениеОбОшибке) Тогда
				СообщениеОбОшибке = СообщениеОбОшибке + Символы.ПС;
			КонецЕсли;
			
			СообщениеОбОшибке = СообщениеОбОшибке + СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(НСтр("ru = 'Не удалось подключиться к серверу %1:
				|%2'"), НастройкиУчетнойЗаписи.ПротоколВходящейПочты, ТекстОшибки);
		КонецЕсли;
		
		Если Не НастройкиУчетнойЗаписи.ИспользоватьДляОтправки Тогда
			ДополнительноеСообщение = Символы.ПС + НСтр("ru = '(Выполнена проверка получения электронных сообщений.)'");
		КонецЕсли;
		
	КонецЕсли;
	
КонецПроцедуры

// Отключает все учетные записи. Используется при начальной настройке узла РИБ.
Процедура ОтключитьИспользованиеУчетныхЗаписей()
	
	ТекстЗапроса =
	"ВЫБРАТЬ
	|	УчетныеЗаписиЭлектроннойПочты.Ссылка
	|ИЗ
	|	Справочник.УчетныеЗаписиЭлектроннойПочты КАК УчетныеЗаписиЭлектроннойПочты
	|ГДЕ
	|	УчетныеЗаписиЭлектроннойПочты.ИспользоватьДляПолучения
	|
	|ОБЪЕДИНИТЬ ВСЕ
	|
	|ВЫБРАТЬ
	|	УчетныеЗаписиЭлектроннойПочты.Ссылка
	|ИЗ
	|	Справочник.УчетныеЗаписиЭлектроннойПочты КАК УчетныеЗаписиЭлектроннойПочты
	|ГДЕ
	|	УчетныеЗаписиЭлектроннойПочты.ИспользоватьДляОтправки";
	
	Запрос = Новый Запрос(ТекстЗапроса);
	Выборка = Запрос.Выполнить().Выбрать(); // АПК:1328 блокировка данных не требуется при выполнении начальной настройки узла РИБ.
	Пока Выборка.Следующий() Цикл
		УчетнаяЗапись = Выборка.Ссылка.ПолучитьОбъект();
		УчетнаяЗапись.ИспользоватьДляОтправки = Ложь;
		УчетнаяЗапись.ИспользоватьДляПолучения = Ложь;
		УчетнаяЗапись.ОбменДанными.Загрузка = Истина;
		УчетнаяЗапись.Записать(); // АПК:1327 блокировка данных не требуется при выполнении начальной настройки узла РИБ.
	КонецЦикла;
	
КонецПроцедуры

// Процедура является обработчиком событий ПриПолученииДанныхОтГлавного и ПриПолученииДанныхОтПодчиненного, возникающих
// при обмене данными в распределенной информационной базе.
//
// Параметры:
//   см. описание соответствующих обработчиков событий в синтакс-помощнике.
//
Процедура ПриПолученииДанных(ЭлементДанных, ПолучениеЭлемента, ОтправкаНазад, Отправитель)
	
	Если ТипЗнч(ЭлементДанных) = Тип("СправочникОбъект.УчетныеЗаписиЭлектроннойПочты") Тогда
		Если ЭлементДанных.ЭтоНовый() Тогда
			ЭлементДанных.ИспользоватьДляПолучения = Ложь;
			ЭлементДанных.ИспользоватьДляОтправки = Ложь;
		Иначе
			ЭлементДанных.ИспользоватьДляПолучения = ОбщегоНазначения.ЗначениеРеквизитаОбъекта(ЭлементДанных.Ссылка, "ИспользоватьДляПолучения");
			ЭлементДанных.ИспользоватьДляОтправки = ОбщегоНазначения.ЗначениеРеквизитаОбъекта(ЭлементДанных.Ссылка, "ИспользоватьДляОтправки");
		КонецЕсли;
	КонецЕсли;
	
КонецПроцедуры

Процедура ПодготовитьВложения(Вложения, НастройкиСохранения) Экспорт
	Перем ЗаписьZipФайла, ИмяАрхива;
	
	Результат = Новый Массив;
	
	// подготовка архива
	ЕстьДобавленныеФайлыВАрхив = Ложь;
	Если НастройкиСохранения.УпаковатьВАрхив Тогда
		ИмяАрхива = ПолучитьИмяВременногоФайла("zip");
		ЗаписьZipФайла = Новый ЗаписьZipФайла(ИмяАрхива);
	КонецЕсли;
	
	ИмяВременногоКаталога = ПолучитьИмяВременногоФайла();
	СоздатьКаталог(ИмяВременногоКаталога);
	
	ВыбранныеФорматыСохранения = НастройкиСохранения.ФорматыСохранения;
	ТаблицаФорматов = СтандартныеПодсистемыСервер.НастройкиФорматовСохраненияТабличногоДокумента();
	
	ИмяФайлаДляАрхива = Неопределено;
	Для Индекс = -Вложения.ВГраница() По 0 Цикл
		Вложение = Вложения[-Индекс];
		ТабличныйДокумент = ПолучитьИзВременногоХранилища(Вложение.АдресВоВременномХранилище);
		Если ТипЗнч(ТабличныйДокумент) = Тип("ТабличныйДокумент") Тогда 
			АдресВоВременномХранилище = Вложение.АдресВоВременномХранилище;
			Вложения.Удалить(-Индекс);
		Иначе
			Продолжить;
		КонецЕсли;
		
		Если ВычислитьИспользованиеВывода(ТабличныйДокумент) = ИспользованиеВывода.Запретить Тогда
			Продолжить;
		КонецЕсли;
		
		Если ТабличныйДокумент.Защита Тогда
			Продолжить;
		КонецЕсли;
		
		Если ТабличныйДокумент.ВысотаТаблицы = 0 Тогда
			Продолжить;
		КонецЕсли;
		
		Для Каждого ВыбранныйФормат Из ВыбранныеФорматыСохранения Цикл
			ТипФайла = ТипФайлаТабличногоДокумента[ВыбранныйФормат];
			НастройкиФормата = ТаблицаФорматов.НайтиСтроки(Новый Структура("ТипФайлаТабличногоДокумента", ТипФайла))[0];
			ИмяФайла = ОбщегоНазначенияКлиентСервер.ЗаменитьНедопустимыеСимволыВИмениФайла(Вложение.Представление);
			Если ИмяФайлаДляАрхива = Неопределено Тогда
				ИмяФайлаДляАрхива = ИмяФайла + ".zip";
			Иначе
				ИмяФайлаДляАрхива = НСтр("ru = 'Документы'") + ".zip";
			КонецЕсли;
			ИмяФайла = ИмяФайла + "." + НастройкиФормата.Расширение;
			
			Если НастройкиСохранения.ПереводитьИменаФайловВТранслит Тогда
				ИмяФайла = СтроковыеФункции.СтрокаЛатиницей(ИмяФайла);
			КонецЕсли;
			
			ПолноеИмяФайла = ФайловаяСистема.УникальноеИмяФайла(ОбщегоНазначенияКлиентСервер.ДобавитьКонечныйРазделительПути(ИмяВременногоКаталога) + ИмяФайла);
			ТабличныйДокумент.Записать(ПолноеИмяФайла, ТипФайла);
			
			Если ТипФайла = ТипФайлаТабличногоДокумента.HTML Тогда
				ВставитьКартинкиВHTML(ПолноеИмяФайла);
			КонецЕсли;
			
			Если ЗаписьZipФайла <> Неопределено Тогда 
				ЕстьДобавленныеФайлыВАрхив = Истина;
				ЗаписьZipФайла.Добавить(ПолноеИмяФайла);
			Иначе
				ДвоичныеДанные = Новый ДвоичныеДанные(ПолноеИмяФайла);
				АдресВоВременномХранилище = ПоместитьВоВременноеХранилище(ДвоичныеДанные, Новый УникальныйИдентификатор);
				ОписаниеФайла = Новый Структура;
				ОписаниеФайла.Вставить("Представление", ИмяФайла);
				ОписаниеФайла.Вставить("АдресВоВременномХранилище", АдресВоВременномХранилище);
				Если ТипФайла = ТипФайлаТабличногоДокумента.ANSITXT Тогда
					ОписаниеФайла.Вставить("Кодировка", "windows-1251");
				КонецЕсли;
				Результат.Добавить(ОписаниеФайла);
			КонецЕсли;
		КонецЦикла;
	КонецЦикла;
	
	// Если архив подготовлен, записываем и помещаем его во временное хранилище.
	Если ЕстьДобавленныеФайлыВАрхив Тогда 
		ЗаписьZipФайла.Записать();
		ДвоичныеДанные = Новый ДвоичныеДанные(ИмяАрхива);
		
		// Используем имеющийся адрес во временном хранилище, привязанный к форме.
		ПоместитьВоВременноеХранилище(ДвоичныеДанные, АдресВоВременномХранилище);
		
		ОписаниеФайла = Новый Структура;
		ОписаниеФайла.Вставить("Представление", ИмяФайлаДляАрхива);
		ОписаниеФайла.Вставить("АдресВоВременномХранилище", АдресВоВременномХранилище);
		Результат.Добавить(ОписаниеФайла);
	КонецЕсли;
	
	Для Каждого ОписаниеФайла Из Результат Цикл
		Вложения.Добавить(ОписаниеФайла);
	КонецЦикла;
		
	УдалитьФайлы(ИмяВременногоКаталога);
	Если ЗначениеЗаполнено(ИмяАрхива) Тогда
		УдалитьФайлы(ИмяАрхива);
	КонецЕсли;
	
КонецПроцедуры

Функция ВычислитьИспользованиеВывода(ТабличныйДокумент)
	Если ТабличныйДокумент.Вывод = ИспользованиеВывода.Авто Тогда
		Возврат ?(ПравоДоступа("Вывод", Метаданные), ИспользованиеВывода.Разрешить, ИспользованиеВывода.Запретить);
	Иначе
		Возврат ТабличныйДокумент.Вывод;
	КонецЕсли;
КонецФункции

Процедура ВставитьКартинкиВHTML(ИмяФайлаHTML)
	
	ТекстовыйДокумент = Новый ТекстовыйДокумент();
	ТекстовыйДокумент.Прочитать(ИмяФайлаHTML, КодировкаТекста.UTF8);
	ТекстHTML = ТекстовыйДокумент.ПолучитьТекст();
	
	ФайлHTML = Новый Файл(ИмяФайлаHTML);
	
	ИмяКаталогаКартинок = ФайлHTML.ИмяБезРасширения + "_files";
	ПутьКаталогаКартинок = СтрЗаменить(ФайлHTML.ПолноеИмя, ФайлHTML.Имя, ИмяКаталогаКартинок);
	
	// Ожидается, что в каталоге будут только картинки.
	ФайлыКартинок = НайтиФайлы(ПутьКаталогаКартинок, "*");
	
	Для Каждого ФайлКартинки Из ФайлыКартинок Цикл
		КартинкаТекстом = Base64Строка(Новый ДвоичныеДанные(ФайлКартинки.ПолноеИмя));
		КартинкаТекстом = "data:image/" + Сред(ФайлКартинки.Расширение,2) + ";base64," + Символы.ПС + КартинкаТекстом;
		
		ТекстHTML = СтрЗаменить(ТекстHTML, ИмяКаталогаКартинок + "\" + ФайлКартинки.Имя, КартинкаТекстом);
	КонецЦикла;
		
	ТекстовыйДокумент.УстановитьТекст(ТекстHTML);
	ТекстовыйДокумент.Записать(ИмяФайлаHTML, КодировкаТекста.UTF8);
	
КонецПроцедуры

Функция НастройкиПодсистемы() Экспорт
	Настройки = Новый Структура;
	Настройки.Вставить("ДоступноПолучениеПисем", Не СтандартныеПодсистемыСервер.ЭтоБазоваяВерсияКонфигурации());
	РаботаСПочтовымиСообщениямиПереопределяемый.ПриОпределенииНастроек(Настройки);
	Возврат Настройки;
КонецФункции

Функция ОпределитьТипСодержимогоПоИмениФайла(ИмяФайла)
	Расширение = "";
	Позиция = СтрНайти(ИмяФайла, ".", НаправлениеПоиска.СКонца);
	Если Позиция > 0 Тогда
		Расширение = НРег(Сред(ИмяФайла, Позиция + 1));
	КонецЕсли;
	Возврат ТипыСодержимого()[Расширение];
КонецФункции

Функция ТипыСодержимого()
	Результат = Новый Соответствие;
	
	Результат.Вставить("json", "application/json");
	Результат.Вставить("pdf", "application/pdf");
	Результат.Вставить("xhtml", "application/xhtml+xml");
	Результат.Вставить("zip", "application/zip");
	Результат.Вставить("gzip", "application/gzip");
	
	Результат.Вставить("aac", "audio/aac");
	Результат.Вставить("ogg", "audio/ogg");
	Результат.Вставить("wma", "audio/x-ms-wma");
	Результат.Вставить("wav", "audio/vnd.wave");
	
	Результат.Вставить("gif", "image/gif");
	Результат.Вставить("jpeg", "image/jpeg");
	Результат.Вставить("png", "image/png");
	Результат.Вставить("svg", "image/svg");
	Результат.Вставить("tiff", "image/tiff");
	Результат.Вставить("ico", "image/vnd.microsoft.icon");
	
	Результат.Вставить("html", "text/html");
	Результат.Вставить("txt", "text/plain");
	Результат.Вставить("xml", "text/xml");
	
	Результат.Вставить("mpeg", "video/mpeg");
	Результат.Вставить("mp4", "video/mp4");
	Результат.Вставить("mov", "video/quicktime");
	Результат.Вставить("wmv", "video/x-ms-wmv");
	Результат.Вставить("flv", "video/x-flv");
	Результат.Вставить("3gpp", "video/3gpp");
	Результат.Вставить("3gp", "video/3gpp");
	Результат.Вставить("3gpp2", "video/3gpp2");
	Результат.Вставить("3g2", "video/3gpp2");
	
	Результат.Вставить("odt", "application/vnd.oasis.opendocument.text");
	Результат.Вставить("ods", "application/vnd.oasis.opendocument.spreadsheet");
	Результат.Вставить("odp", "application/vnd.oasis.opendocument.presentation");
	Результат.Вставить("odg", "application/vnd.oasis.opendocument.graphics");
	
	Результат.Вставить("doc", "application/msword");
	Результат.Вставить("docx", "application/vnd.openxmlformats-officedocument.wordprocessingml.document");
	Результат.Вставить("xls", "application/vnd.ms-excel");
	Результат.Вставить("xlsx", "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
	Результат.Вставить("ppt", "application/vnd.ms-powerpoint");
	Результат.Вставить("pptx", "application/vnd.openxmlformats-officedocument.presentationml.presentation");
	
	Результат.Вставить("rar", "application/x-rar-compressed");
	
	Результат.Вставить("p7m", "application/x-pkcs7-mime");
	Результат.Вставить("p7s", "application/x-pkcs7-signature");
	
	Возврат Результат;
КонецФункции

Функция ПолучитьHTMLФорматированногоДокументаДляПисьма(ФорматированныйДокумент)
	
	// Выгрузка форматированного документа в HTML текст и картинки.
	ТекстHTML = "";
	Картинки = Новый Структура;
	ФорматированныйДокумент.ПолучитьHTML(ТекстHTML, Картинки);
	
	// Конвертация HTML текста в ДокументHTML.
	Построитель = Новый ПостроительDOM;
	ЧтениеHTML = Новый ЧтениеHTML;
	ЧтениеHTML.УстановитьСтроку(ТекстHTML);
	ДокументHTML = Построитель.Прочитать(ЧтениеHTML);
	
	// Замена имен картинок в документе HTML на идентификаторы.
	Для Каждого Картинка Из ДокументHTML.Картинки Цикл
		АтрибутИсточникКартинки = Картинка.Атрибуты.ПолучитьИменованныйЭлемент("src");
		Если СтрНачинаетсяС(АтрибутИсточникКартинки.ТекстовоеСодержимое, "data:") Тогда
			Продолжить;
		КонецЕсли;
		Картинка.УстановитьАтрибут("alt", АтрибутИсточникКартинки.ТекстовоеСодержимое);
		АтрибутИсточникКартинки.ТекстовоеСодержимое = "cid:" + АтрибутИсточникКартинки.ТекстовоеСодержимое;
	КонецЦикла;
	
	// Конвертация ДокументHTML обратно в текст HTML.
	ЗаписьDOM = Новый ЗаписьDOM;
	ЗаписьHTML = Новый ЗаписьHTML;
	ЗаписьHTML.УстановитьСтроку();
	ЗаписьDOM.Записать(ДокументHTML, ЗаписьHTML);
	ТекстHTML = ЗаписьHTML.Закрыть();
	
	// Подготовка результата.
	Результат = Новый Структура;
	Результат.Вставить("ТекстHTML", ТекстHTML);
	Результат.Вставить("Картинки", Картинки);
	
	Возврат Результат;
	
КонецФункции

Функция ПредставлениеПисьма(ТемаПисьма, ДатаПисьма)
	
	ШаблонПредставления = НСтр("ru = '%1 от %2'");
	
	Возврат СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(ШаблонПредставления,
		?(ПустаяСтрока(ТемаПисьма), НСтр("ru = '<Без темы>'"), ТемаПисьма),
		Формат(ДатаПисьма, "ДЛФ=D"));
	
КонецФункции

// Преобразует к единому виду коллекцию переданных вложений.
// Требуется для обхода случаев, когда исходная форма не заботится о времени жизни временного хранилища, в 
// которое помещены вложения. Вложения перекладываются во временное хранилище "на время сеанса".
//
Функция ОписанияВложений(КоллекцияВложений) Экспорт
	Если ТипЗнч(КоллекцияВложений) <> Тип("СписокЗначений") И ТипЗнч(КоллекцияВложений) <> Тип("Массив") Тогда
		Возврат КоллекцияВложений;
	КонецЕсли;
	
	Результат = Новый Массив;
	Для Каждого Вложение Из КоллекцияВложений Цикл
		ОписаниеВложения = ОписаниеВложения();
		Если ТипЗнч(КоллекцияВложений) = Тип("СписокЗначений") Тогда
			ОписаниеВложения.Представление = Вложение.Представление;
			ДвоичныеДанные = Неопределено;
			Если ТипЗнч(Вложение.Значение) = Тип("ДвоичныеДанные") Тогда
				ДвоичныеДанные = Вложение.Значение;
			Иначе
				Если ЭтоАдресВременногоХранилища(Вложение.Значение) Тогда
					ДвоичныеДанные = ПолучитьИзВременногоХранилища(Вложение.Значение);
				Иначе
					ПутьКФайлу = Вложение.Значение;
					ДвоичныеДанные = Новый ДвоичныеДанные(ПутьКФайлу);
				КонецЕсли;
			КонецЕсли;
		Иначе // ТипЗнч(Параметры.Вложения) = "массив структур"
			ДвоичныеДанные = ПолучитьИзВременногоХранилища(Вложение.АдресВоВременномХранилище);
			ЗаполнитьЗначенияСвойств(ОписаниеВложения, Вложение, , "АдресВоВременномХранилище");
		КонецЕсли;
		ОписаниеВложения.АдресВоВременномХранилище = ПоместитьВоВременноеХранилище(ДвоичныеДанные, Новый УникальныйИдентификатор);
		Результат.Добавить(ОписаниеВложения);
	КонецЦикла;
	
	Возврат Результат;
КонецФункции

Функция ОписаниеВложения()
	Результат = Новый Структура;
	Результат.Вставить("Представление");
	Результат.Вставить("АдресВоВременномХранилище");
	Результат.Вставить("Кодировка");
	Результат.Вставить("Идентификатор");
	
	Возврат Результат;
КонецФункции

Функция ПочтовыйСерверХранитПисьмаОтправленныеПоSMTP(ИнтернетПочтовыйПрофиль)
	
	Возврат НРег(ИнтернетПочтовыйПрофиль.АдресСервераSMTP) = "smtp.gmail.com"
		Или СтрЗаканчиваетсяНа(НРег(ИнтернетПочтовыйПрофиль.АдресСервераSMTP), ".outlook.com") > 0;
	
КонецФункции

Функция ЕстьВнешниеРесурсы(ДокументHTML) Экспорт
	
	Фильтры = Новый Массив;
	Фильтры.Добавить(ФильтрПоАтрибуту("src", "^(http|https)://"));
	
	Фильтр = ОбъединитьФильтры(Фильтры);
	НайденныеУзлы = ДокументHTML.НайтиПоФильтру(ОбщегоНазначения.ЗначениеВJSON(Фильтр));
	
	Возврат НайденныеУзлы.Количество() > 0;
	
КонецФункции

Процедура ОтключитьНебезопасноеСодержимое(ДокументHTML, ОтключитьВнешниеРесурсы = Истина) Экспорт
	
	Фильтры = Новый Массив;
	Фильтры.Добавить(ФильтрПоИмениУзла("script"));
	Фильтры.Добавить(ФильтрПоИмениУзла("link"));
	Фильтры.Добавить(ФильтрПоИмениУзла("iframe"));
	Фильтры.Добавить(ФильтрПоИмениАтрибута("onerror"));
	Фильтры.Добавить(ФильтрПоИмениАтрибута("onmouseover"));
	Фильтры.Добавить(ФильтрПоИмениАтрибута("onmouseout"));
	Фильтры.Добавить(ФильтрПоИмениАтрибута("onclick"));
	Фильтры.Добавить(ФильтрПоИмениАтрибута("onload"));
	
	Фильтр = ОбъединитьФильтры(Фильтры);
	ДокументHTML.УдалитьПоФильтру(ОбщегоНазначения.ЗначениеВJSON(Фильтр));
	
	Если ОтключитьВнешниеРесурсы Тогда
		Фильтр = ФильтрПоАтрибуту("src", "^(http|https)://");
		НайденныеУзлы = ДокументHTML.НайтиПоФильтру(ОбщегоНазначения.ЗначениеВJSON(Фильтр));
		Для Каждого Узел Из НайденныеУзлы Цикл
			Узел.Значение = "";
		КонецЦикла;
	КонецЕсли;
	
КонецПроцедуры

Функция ФильтрПоИмениУзла(ИмяУзла)
	
	Результат = Новый Структура;
	Результат.Вставить("type", "elementname");
	Результат.Вставить("value", Новый Структура("value, operation", ИмяУзла, "equals"));
	
	Возврат Результат;
	
КонецФункции

Функция ОбъединитьФильтры(Фильтры, ТипОбъединения = "Или")
	
	Если Фильтры.Количество() = 1 Тогда
		Возврат Фильтры[0];
	КонецЕсли;
	
	Результат = Новый Структура;
	Результат.Вставить("type", ?(ТипОбъединения = "И", "intersection", "union"));
	Результат.Вставить("value", Фильтры);
	
	Возврат Результат;
	
КонецФункции

Функция ФильтрПоАтрибуту(ИмяАтрибута, ШаблонЗначения)
	
	Фильтры = Новый Массив;
	Фильтры.Добавить(ФильтрПоИмениАтрибута(ИмяАтрибута));
	Фильтры.Добавить(ФильтрПоЗначениюАтрибута(ШаблонЗначения));
	
	Результат = ОбъединитьФильтры(Фильтры, "И");
	
	Возврат Результат;
	
КонецФункции

Функция ФильтрПоИмениАтрибута(ИмяАтрибута)
	
	Результат = Новый Структура;
	Результат.Вставить("type", "attribute");
	Результат.Вставить("value", Новый Структура("value, operation", ИмяАтрибута, "nameequals"));
	
	Возврат Результат;
	
КонецФункции

Функция ФильтрПоЗначениюАтрибута(ШаблонЗначения)
	
	Результат = Новый Структура;
	Результат.Вставить("type", "attribute");
	Результат.Вставить("value", Новый Структура("value, operation", ШаблонЗначения, "valuematchesregex"));
	
	Возврат Результат;
	
КонецФункции

Функция ОтправитьПисьмо(УчетнаяЗапись, Письмо) Экспорт
	
	Письма = ОбщегоНазначенияКлиентСервер.ЗначениеВМассиве(Письмо);
	Возврат ОтправитьПисьма(УчетнаяЗапись, Письма)[Письмо];
	
КонецФункции

// См. РаботаСПочтовымиСообщениями.ОтправитьПисьма
Функция ОтправитьПисьма(УчетнаяЗапись, Письма, ТекстИсключения = Неопределено) Экспорт
	
	РеквизитыОтправителя = ОбщегоНазначения.ЗначенияРеквизитовОбъекта(УчетнаяЗапись, "ИмяПользователя,АдресЭлектроннойПочты,ОтправлятьСкрытыеКопииПисемНаЭтотАдрес,ИспользоватьДляПолучения");
	
	УстановитьОтключениеБезопасногоРежима(Истина);
	Профиль = ИнтернетПочтовыйПрофиль(УчетнаяЗапись);
	УстановитьОтключениеБезопасногоРежима(Ложь);
	
	УстановитьОтключениеБезопасногоРежима(Истина);
	
	ПротоколПолученияПочты = ПротоколИнтернетПочты.POP3;
	Если ИспользоватьIMAPПриОтправкеПисем(Профиль) Тогда
		ПротоколПолученияПочты = ПротоколИнтернетПочты.IMAP;
	КонецЕсли;
	
	ТекстОшибки = "";
	Попытка
		Соединение = Новый ИнтернетПочта;
		Соединение.Подключиться(Профиль, ПротоколПолученияПочты);
		Если ПротоколПолученияПочты = ПротоколИнтернетПочты.IMAP Тогда
			ОпределитьПапкуОтправленные(Соединение);
		КонецЕсли;
	Исключение
		ТекстОшибки = РасширенноеПредставлениеОшибки(ИнформацияОбОшибке(), ОбщегоНазначения.КодОсновногоЯзыка());
		ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
			НСтр("ru = 'Не удалось подключиться к серверу IMAP:
			|%1'", ОбщегоНазначения.КодОсновногоЯзыка()), ТекстОшибки);
		
		Если ПротоколПолученияПочты = ПротоколИнтернетПочты.IMAP И Не РеквизитыОтправителя.ИспользоватьДляПолучения Тогда
			ЗаписьЖурналаРегистрации(ИмяСобытияОтправкаПочты(), УровеньЖурналаРегистрации.Ошибка, 
				Метаданные.Справочники.УчетныеЗаписиЭлектроннойПочты, УчетнаяЗапись, ТекстОшибки);
			ПротоколПолученияПочты = ПротоколИнтернетПочты.POP3;
			Соединение.Подключиться(Профиль, ПротоколПолученияПочты);
		Иначе
			ВызватьИсключение;
		КонецЕсли;
	КонецПопытки;
	
	РезультатыОтправкиПисем = Новый Соответствие;
	
	ОбрабатыватьТексты = ОбработкаТекстаИнтернетПочтовогоСообщения.НеОбрабатывать;
	
	Попытка
		Для Каждого Письмо Из Письма Цикл
			Письмо.ИмяОтправителя = РеквизитыОтправителя.ИмяПользователя;
			Письмо.Отправитель.ОтображаемоеИмя = РеквизитыОтправителя.ИмяПользователя;
			Письмо.Отправитель.Адрес = РеквизитыОтправителя.АдресЭлектроннойПочты;
			
			Если РеквизитыОтправителя.ОтправлятьСкрытыеКопииПисемНаЭтотАдрес Тогда
				Получатель = Письмо.СлепыеКопии.Добавить(РеквизитыОтправителя.АдресЭлектроннойПочты);
				Получатель.ОтображаемоеИмя = РеквизитыОтправителя.ИмяПользователя;
			КонецЕсли;
			
			РезультатОтправкиПисьма = Новый Структура;
			РезультатОтправкиПисьма.Вставить("ОшибочныеПолучатели", Новый Соответствие);
			РезультатОтправкиПисьма.Вставить("ИдентификаторПисьмаSMTP", "");
			РезультатОтправкиПисьма.Вставить("ИдентификаторПисьмаIMAP", "");
			
			КодироватьАдресаВПисьме(Письмо);
			
			Если ПротоколПолученияПочты = ПротоколИнтернетПочты.IMAP Тогда
				Соединение.Послать(Письмо, ОбрабатыватьТексты, ПротоколИнтернетПочты.IMAP);
				РезультатОтправкиПисьма.Вставить("ИдентификаторПисьмаIMAP", Письмо.ИдентификаторСообщения);
				
				ФлагиПисьма = Новый ФлагиИнтернетПочтовогоСообщения;
				ФлагиПисьма.Прочитанное = Истина;
				ФлагиПисем = Новый Соответствие;
				ФлагиПисем.Вставить(Письмо.ИдентификаторСообщения, ФлагиПисьма);
				Соединение.УстановитьФлагиСообщений(ФлагиПисем);
			КонецЕсли;
			
			ОшибочныеПолучатели = Новый Соответствие;
			Попытка
				ОшибочныеПолучатели = Соединение.Послать(Письмо, ОбрабатыватьТексты, ПротоколИнтернетПочты.SMTP);
			Исключение
				ИнформацияОбОшибке = ИнформацияОбОшибке();
				ТекстОшибки = ОбработкаОшибок.КраткоеПредставлениеОшибки(ИнформацияОбОшибке);
				Если ПолучательПисьмаОтклоненСервером(ТекстОшибки) Тогда
					Для Каждого Получатель Из Письмо.Получатели Цикл
						ОшибочныеПолучатели.Вставить(Получатель.Адрес, ТекстОшибки);
					КонецЦикла;
				Иначе
					ВызватьИсключение;
				КонецЕсли;
			КонецПопытки;
			
			РезультатОтправкиПисьма.ОшибочныеПолучатели = ОшибочныеПолучатели;
			РезультатОтправкиПисьма.ИдентификаторПисьмаSMTP = Письмо.ИдентификаторСообщения;
			
			Если ОшибочныеПолучатели.Количество() > 0 Тогда
				ТекстыОшибок = Новый Массив;
				Для Каждого ОшибочныйПолучатель Из ОшибочныеПолучатели Цикл
					Получатель = ОшибочныйПолучатель.Ключ;
					ТекстОшибки = ОшибочныйПолучатель.Значение;
					ТекстыОшибок.Добавить(СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
						НСтр("ru = '%1: %2'"), Получатель, ТекстОшибки));
				КонецЦикла;
				ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(НСтр("ru = 'Отправка письма следующим получателям не выполнена:
					|%1'", ОбщегоНазначения.КодОсновногоЯзыка()), СтрСоединить(ТекстыОшибок, Символы.ПС));
				ЗаписьЖурналаРегистрации(ИмяСобытияОтправкаПочты(), УровеньЖурналаРегистрации.Ошибка, , УчетнаяЗапись, ТекстОшибки);
			КонецЕсли;
			
			РезультатыОтправкиПисем.Вставить(Письмо, РезультатОтправкиПисьма);
		КонецЦикла;
	Исключение
		Попытка
			Соединение.Отключиться();
		Исключение // АПК:280
			// Обработка и журналирование исключения не требуется, т.к. 
			// в вызывающий код передается исходное исключение, которое будет там обработано.
		КонецПопытки;

		ТекстОшибки = РасширенноеПредставлениеОшибки(ИнформацияОбОшибке(), ОбщегоНазначения.КодОсновногоЯзыка());

		ЗаписьЖурналаРегистрации(ИмяСобытияОтправкаПочты(), УровеньЖурналаРегистрации.Ошибка, , УчетнаяЗапись, ТекстОшибки);
		ТекстИсключения = ОбработкаОшибок.КраткоеПредставлениеОшибки(ИнформацияОбОшибке());

		Если РезультатыОтправкиПисем.Количество() = 0 Тогда
			ВызватьИсключение;
		Иначе
			Возврат РезультатыОтправкиПисем;
		КонецЕсли;
	КонецПопытки;
	
	Соединение.Отключиться();
	УстановитьОтключениеБезопасногоРежима(Ложь);
	
	Возврат РезультатыОтправкиПисем;
	
КонецФункции

Функция ИмяСобытияОтправкаПочты()
	
	Возврат НСтр("ru = 'Работа с почтовыми сообщениями.Отправка почты'", ОбщегоНазначения.КодОсновногоЯзыка());

КонецФункции

Функция ПодготовитьПисьмо(УчетнаяЗапись, ПараметрыПисьма) Экспорт
	
	Письмо = Новый ИнтернетПочтовоеСообщение;
	
	РеквизитыОтправителя = ОбщегоНазначения.ЗначенияРеквизитовОбъекта(УчетнаяЗапись, "ИмяПользователя,АдресЭлектроннойПочты");
	Письмо.ИмяОтправителя              = РеквизитыОтправителя.ИмяПользователя;
	Письмо.Отправитель.ОтображаемоеИмя = РеквизитыОтправителя.ИмяПользователя;
	Письмо.Отправитель.Адрес           = РеквизитыОтправителя.АдресЭлектроннойПочты;
	
	Если ПараметрыПисьма.Свойство("Тема") Тогда
		Письмо.Тема = ПараметрыПисьма.Тема;
	КонецЕсли;
	
	Кому = ПараметрыПисьма.Кому;
	Если ТипЗнч(Кому) = Тип("Строка") Тогда
		Кому = ОбщегоНазначенияКлиентСервер.РазобратьСтрокуСПочтовымиАдресами(Кому);
	КонецЕсли;
	Для Каждого ПочтовыйАдресПолучателя Из Кому Цикл
		Получатель = Письмо.Получатели.Добавить(ПочтовыйАдресПолучателя.Адрес);
		Получатель.ОтображаемоеИмя = ПочтовыйАдресПолучателя.Представление;
	КонецЦикла;
	
	Если ПараметрыПисьма.Свойство("Копии") Тогда
		Для Каждого ПочтовыйАдресПолучателяКопии Из ПараметрыПисьма.Копии Цикл
			Получатель = Письмо.Копии.Добавить(ПочтовыйАдресПолучателяКопии.Адрес);
			Получатель.ОтображаемоеИмя = ПочтовыйАдресПолучателяКопии.Представление;
		КонецЦикла;
	КонецЕсли;
	
	Если ПараметрыПисьма.Свойство("СкрытыеКопии") Тогда
		Для Каждого СведенияОПолучателе Из ПараметрыПисьма.СкрытыеКопии Цикл
			Получатель = Письмо.СлепыеКопии.Добавить(СведенияОПолучателе.Адрес);
			Получатель.ОтображаемоеИмя = СведенияОПолучателе.Представление;
		КонецЦикла;
	КонецЕсли;
	
	Если ПараметрыПисьма.Свойство("АдресОтвета") Тогда
		Для Каждого ПочтовыйАдресОтвета Из ПараметрыПисьма.АдресОтвета Цикл
			ПочтовыйАдресОбратный = Письмо.ОбратныйАдрес.Добавить(ПочтовыйАдресОтвета.Адрес);
			ПочтовыйАдресОбратный.ОтображаемоеИмя = ПочтовыйАдресОтвета.Представление;
		КонецЦикла;
	КонецЕсли;
	
	Вложения = Неопределено;
	ПараметрыПисьма.Свойство("Вложения", Вложения);
	Если Вложения <> Неопределено Тогда
		Для Каждого Вложение Из Вложения Цикл
			Если ТипЗнч(Вложение) = Тип("Структура") Тогда
				ДанныеФайла = Неопределено;
				Если ЭтоАдресВременногоХранилища(Вложение.АдресВоВременномХранилище) Тогда
					ДанныеФайла = ПолучитьИзВременногоХранилища(Вложение.АдресВоВременномХранилище);
				Иначе
					ДанныеФайла = Вложение.АдресВоВременномХранилище;
				КонецЕсли;
				НовоеВложение = Письмо.Вложения.Добавить(ДанныеФайла, Вложение.Представление);
				Если Вложение.Свойство("Кодировка") И Не ПустаяСтрока(Вложение.Кодировка) Тогда
					НовоеВложение.Кодировка = Вложение.Кодировка;
				КонецЕсли;
				Если Вложение.Свойство("Идентификатор") Тогда
					НовоеВложение.Идентификатор = Вложение.Идентификатор;
				КонецЕсли;
			Иначе // Поддержка обратной совместимости с 2.2.1.
				Если ТипЗнч(Вложение.Значение) = Тип("Структура") Тогда
					НовоеВложение = Письмо.Вложения.Добавить(Вложение.Значение.ДвоичныеДанные, Вложение.Ключ);
					Если Вложение.Значение.Свойство("Идентификатор") Тогда
						НовоеВложение.Идентификатор = Вложение.Значение.Идентификатор;
					КонецЕсли;
					Если Вложение.Значение.Свойство("Кодировка") Тогда
						НовоеВложение.Кодировка = Вложение.Значение.Кодировка;
					КонецЕсли;
					Если Вложение.Значение.Свойство("ТипСодержимого") Тогда
						НовоеВложение.ТипСодержимого = Вложение.Значение.ТипСодержимого;
					КонецЕсли;
					Если Вложение.Значение.Свойство("Имя") Тогда
						НовоеВложение.Имя = Вложение.Значение.Имя;
					КонецЕсли;
				Иначе
					ИнтернетПочтовоеВложение = Письмо.Вложения.Добавить(Вложение.Значение, Вложение.Ключ);
					Если ТипЗнч(Вложение.Значение) = Тип("ИнтернетПочтовоеСообщение") Тогда
						ИнтернетПочтовоеВложение.ТипСодержимого = "message/rfc822";
					КонецЕсли;
				КонецЕсли;
			КонецЕсли;
		КонецЦикла;
	КонецЕсли;
	
	Для Каждого Вложение Из Письмо.Вложения Цикл
		Если Не ЗначениеЗаполнено(Вложение.ТипСодержимого) Тогда
			ТипСодержимого = ОпределитьТипСодержимогоПоИмениФайла(Вложение.Имя);
			Если ЗначениеЗаполнено(ТипСодержимого) Тогда
				Вложение.ТипСодержимого = ТипСодержимого;
			КонецЕсли;
		КонецЕсли;
	КонецЦикла;
	
	Если ПараметрыПисьма.Свойство("ИдентификаторыОснований") Тогда
		Письмо.УстановитьПолеЗаголовка("References", ПараметрыПисьма.ИдентификаторыОснований);
	КонецЕсли;
	
	Тело = "";
	ПараметрыПисьма.Свойство("Тело", Тело);
	
	ТипТекста = Неопределено;
	Если ТипЗнч(Тело) = Тип("ФорматированныйДокумент") Тогда
		СодержимоеПисьма = ПолучитьHTMLФорматированногоДокументаДляПисьма(Тело);
		Тело = СодержимоеПисьма.ТекстHTML;
		Картинки = СодержимоеПисьма.Картинки;
		ТипТекста = ТипТекстаПочтовогоСообщения.HTML;
		
		Для Каждого Картинка Из Картинки Цикл
			ИмяКартинки = Картинка.Ключ;
			ДанныеКартинки = Картинка.Значение;
			Вложение = Письмо.Вложения.Добавить(ДанныеКартинки.ПолучитьДвоичныеДанные(), ИмяКартинки);
			Вложение.Идентификатор = ИмяКартинки;
		КонецЦикла;
	КонецЕсли;
	Текст = Письмо.Тексты.Добавить(Тело);
	Если ЗначениеЗаполнено(ТипТекста) Тогда
		Текст.ТипТекста = ТипТекста;
	КонецЕсли;
	
	Если ТипТекста = Неопределено Тогда
		Если ПараметрыПисьма.Свойство("ТипТекста", ТипТекста) Тогда
			Если ТипЗнч(ТипТекста) = Тип("Строка") Тогда
				Если      ТипТекста = "HTML" Тогда
					Текст.ТипТекста = ТипТекстаПочтовогоСообщения.HTML;
				ИначеЕсли ТипТекста = "RichText" Тогда
					Текст.ТипТекста = ТипТекстаПочтовогоСообщения.РазмеченныйТекст;
				Иначе
					Текст.ТипТекста = ТипТекстаПочтовогоСообщения.ПростойТекст;
				КонецЕсли;
			ИначеЕсли ТипЗнч(ТипТекста) = Тип("ПеречислениеСсылка.ТипыТекстовЭлектронныхПисем") Тогда
				Если      ТипТекста = Перечисления.ТипыТекстовЭлектронныхПисем.HTML
					ИЛИ ТипТекста = Перечисления.ТипыТекстовЭлектронныхПисем.HTMLСКартинками Тогда
					Текст.ТипТекста = ТипТекстаПочтовогоСообщения.HTML;
				ИначеЕсли ТипТекста = Перечисления.ТипыТекстовЭлектронныхПисем.РазмеченныйТекст Тогда
					Текст.ТипТекста = ТипТекстаПочтовогоСообщения.РазмеченныйТекст;
				Иначе
					Текст.ТипТекста = ТипТекстаПочтовогоСообщения.ПростойТекст;
				КонецЕсли;
			Иначе
				Текст.ТипТекста = ТипТекста;
			КонецЕсли;
		Иначе
			Текст.ТипТекста = ТипТекстаПочтовогоСообщения.ПростойТекст;
		КонецЕсли;
	КонецЕсли;
	
	Важность = Неопределено;
	Если ПараметрыПисьма.Свойство("Важность", Важность) Тогда
		Письмо.Важность = Важность;
	КонецЕсли;
	
	Кодировка = Неопределено;
	Если ПараметрыПисьма.Свойство("Кодировка", Кодировка) Тогда
		Письмо.Кодировка = Кодировка;
	КонецЕсли;
	
	Если ПараметрыПисьма.Свойство("УведомитьОДоставке") Тогда
		Письмо.УведомитьОДоставке = ПараметрыПисьма.УведомитьОДоставке;
	КонецЕсли;
	
	Если ПараметрыПисьма.Свойство("УведомитьОПрочтении") Тогда
		Письмо.УведомитьОПрочтении = ПараметрыПисьма.УведомитьОПрочтении;
		Письмо.АдресаУведомленияОПрочтении.Добавить(РеквизитыОтправителя.АдресЭлектроннойПочты);
	КонецЕсли;
	
	Если Не ПараметрыПисьма.Свойство("ОбрабатыватьТексты") Или ПараметрыПисьма.ОбрабатыватьТексты Тогда
		Письмо.ОбработатьТексты();
	КонецЕсли;
	
	Возврат Письмо;
	
КонецФункции

// Возвращает список разрешений для автоматического поиска настроек почты.
//
// Возвращаемое значение:
//  Массив
//
Функция Разрешения() Экспорт
	
	Протокол = "HTTPS";
	Адрес = АдресВнешнегоРесурса();
	Порт = Неопределено;
	Описание = НСтр("ru = 'Поиск настроек почты и диагностика ошибок подключения.'");
	
	МодульРаботаВБезопасномРежиме = ОбщегоНазначения.ОбщийМодуль("РаботаВБезопасномРежиме");
	
	Разрешения = Новый Массив;
	Разрешения.Добавить(
		МодульРаботаВБезопасномРежиме.РазрешениеНаИспользованиеИнтернетРесурса(Протокол, Адрес, Порт, Описание));
	
	Для Каждого Адрес Из АдресаСерверовDNS() Цикл
		Протокол = "TCP";
		Порт = 53;
		Описание = НСтр("ru = 'Поиск настроек почты.'");
	
		Разрешения.Добавить(
			МодульРаботаВБезопасномРежиме.РазрешениеНаИспользованиеИнтернетРесурса(Протокол, Адрес, Порт, Описание));
	КонецЦикла;
	
	Если ОбщегоНазначения.ЭтоWindowsСервер() Тогда
		ШаблонКоманды = "cmd /S /C ""%(nslookup -type=mx % %)%""";
	ИначеЕсли ОбщегоНазначения.ЭтоLinuxСервер() Тогда
		ШаблонКоманды = "nslookup -type=mx % %";
	КонецЕсли;
	Разрешения.Добавить(МодульРаботаВБезопасномРежиме.РазрешениеНаИспользованиеПриложенияОперационнойСистемы(ШаблонКоманды,
		НСтр("ru = 'Разрешение для nslookup.'", ОбщегоНазначения.КодОсновногоЯзыка())));
	
	Возврат Разрешения;
	
КонецФункции

Функция ПолучательПисьмаОтклоненСервером(Знач ТекстОшибки)
	
	ТекстОшибки = НРег(ТекстОшибки);
	Возврат СтрНайти(ТекстОшибки, "invalid mailbox") > 0
		Или СтрНайти(ТекстОшибки, "user not found") > 0;
	
КонецФункции

Функция ПоясненияПоОшибке(ТекстОшибки, Знач КодЯзыка = Неопределено, ДляПомощникаНастройки = Ложь) Экспорт
	
	Если КодЯзыка = Неопределено Тогда
		КодЯзыка = ТекущийЯзык().КодЯзыка;
	КонецЕсли;
	
	ОписанияОшибок = Новый Массив;
	
	Если ОбщегоНазначения.ПодсистемаСуществует("СтандартныеПодсистемы.ПолучениеФайловИзИнтернета") Тогда
		МодульПолучениеФайловИзИнтернета = ОбщегоНазначения.ОбщийМодуль("ПолучениеФайловИзИнтернета");
		АдресФайла = АдресФайлаСОписаниемОшибок();
		ЗагруженныйФайл = МодульПолучениеФайловИзИнтернета.СкачатьФайлНаСервере(АдресФайла);
		Если ЗагруженныйФайл.Статус Тогда
			ЧтениеJSON = Новый ЧтениеJSON();
			ЧтениеJSON.ОткрытьФайл(ЗагруженныйФайл.Путь);
			ОписанияОшибок = ПрочитатьJSON(ЧтениеJSON, Истина);
			ЧтениеJSON.Закрыть();
		КонецЕсли;
	КонецЕсли;
	
	ВозможныеПричины = Новый Массив;
	СпособыУстранения = Новый Массив;
	
	Для Каждого ОписаниеОшибки Из ОписанияОшибок Цикл
		ШаблоныТекста = ОписаниеОшибки["SearchPatterns"];
		Если Не ЗначениеЗаполнено(ШаблоныТекста) Тогда
			Продолжить;
		КонецЕсли;
		
		Для Каждого ШаблонТекста Из ШаблоныТекста Цикл
			Если Не СтрокаСоответствуетШаблону(ТекстОшибки, ШаблонТекста) Тогда
				Продолжить;
			КонецЕсли;
			
			Для Каждого Строка Из СтрРазделить(ЗначениеСвойства("Reason", ОписаниеОшибки, КодЯзыка), Символы.ПС, Ложь) Цикл
				ВозможныеПричины.Добавить(Строка);
			КонецЦикла;
			
			Для Каждого Элемент Из ОписаниеОшибки["HowToFix"] Цикл
				Если Не СпособУстраненияПрименим(Элемент) Тогда
					Продолжить;
				КонецЕсли;

				СпособУстранения = Элемент[КодЯзыка];
				Если СпособУстранения = Неопределено Тогда
					СпособУстранения = Элемент[ОбщегоНазначения.КодОсновногоЯзыка()];
				КонецЕсли;
				СпособыУстранения.Добавить(СпособУстранения);
			КонецЦикла;
		КонецЦикла;
	КонецЦикла;
	
	Если Не ЗначениеЗаполнено(ВозможныеПричины) Тогда
		Если Не ЗначениеЗаполнено(ОписанияОшибок) Тогда
			ВозможныеПричины.Добавить(НСтр("ru = 'Отсутствует подключение к Интернету.'"));
		КонецЕсли;
		ВозможныеПричины.Добавить(НСтр("ru = 'Неверные настройки подключения к почтовому серверу.'"));
	КонецЕсли;
	
	Если Не ЗначениеЗаполнено(СпособыУстранения) Тогда
		Если Не ЗначениеЗаполнено(ОписанияОшибок) Тогда
			СпособыУстранения.Добавить(НСтр("ru = 'Проверьте подключение к Интернету.'"));
		КонецЕсли; 
		
		Если ДляПомощникаНастройки Тогда
			СпособыУстранения.Добавить(НСтр("ru = 'Проверьте введенные настройки.'"));
		Иначе
			СпособыУстранения.Добавить(СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(НСтр(
				"ru = 'Попробуйте перенастроить почту (кнопка <a href=\""%1\"">Перенастроить</a> в настройках почты).'"),
				"Перенастроить"));
		КонецЕсли;
		
		СпособыУстранения.Добавить(НСтр("ru = 'Обратитесь к администратору локальной сети.'"));
		СпособыУстранения.Добавить(НСтр("ru = 'Обратитесь к администратору почтового сервера.'"));
	КонецЕсли;
	
	ВозможныеПричины = ОбщегоНазначенияКлиентСервер.СвернутьМассив(ВозможныеПричины);
	СпособыУстранения = ОбщегоНазначенияКлиентСервер.СвернутьМассив(СпособыУстранения);
	
	Результат = Новый Структура;
	Результат.Вставить("ВозможныеПричины", ФорматированныеСтроки(ВозможныеПричины));
	Результат.Вставить("СпособыУстранения", ФорматированныеСтроки(СпособыУстранения));
	
	Возврат Результат;
	
КонецФункции

Функция ЗначениеСвойства(ИмяСвойства, КоллекцияСвойств, КодЯзыка)
	
	Результат = "";
	
	Если ТипЗнч(КоллекцияСвойств[ИмяСвойства]) = Тип("Соответствие") Тогда
		Результат = КоллекцияСвойств[ИмяСвойства][КодЯзыка];
		Если Не ЗначениеЗаполнено(Результат) Тогда
			Результат = КоллекцияСвойств[ИмяСвойства][ОбщегоНазначения.КодОсновногоЯзыка()];
		КонецЕсли;
	КонецЕсли;
	
	Возврат Результат;
	
КонецФункции

Функция ФорматированныйСписок(Строки) Экспорт
	
	Список = Новый Массив;
	Для Индекс = 0 По Строки.ВГраница() Цикл
		Строка = Строки[Индекс];

		Список.Добавить("• ");
		Список.Добавить(Строка);
		Если Индекс < Строки.ВГраница() Тогда
			Список.Добавить(Символы.ПС + Символы.ПС);
		КонецЕсли;
	КонецЦикла;
	
	Возврат Новый ФорматированнаяСтрока(Список);
	
КонецФункции

Функция ФорматированныеСтроки(Строки)
	
	Результат = Новый Массив;
	Для Каждого Строка Из Строки Цикл
		ФорматированнаяСтрока = СтроковыеФункции.ФорматированнаяСтрока(Строка);
		Результат.Добавить(ФорматированнаяСтрока);
	КонецЦикла;
	
	Возврат Результат;
	
КонецФункции

Функция СпособУстраненияПрименим(СпособУстранения)
	
	Результат = Истина;
	
	Теги = СтрРазделить(НРег(СпособУстранения["Tags"]), ",");
	Для Каждого Тег Из Теги Цикл
		Если Тег = "server" Тогда
			Результат = Результат И Не ОбщегоНазначения.ИнформационнаяБазаФайловая();
		КонецЕсли;
	КонецЦикла;
	
	Возврат Результат;
	
КонецФункции

Функция РасширенноеПредставлениеОшибки(ИнформацияОбОшибке, КодЯзыка, ВключитьПодробноеПредставлениеОшибки = Истина) Экспорт
	
	КраткоеПредставлениеОшибки = ОбработкаОшибок.КраткоеПредставлениеОшибки(ИнформацияОбОшибке);
	ПодробноеПредставлениеОшибки = ОбработкаОшибок.ПодробноеПредставлениеОшибки(ИнформацияОбОшибке);
	ПоясненияПоОшибке = ПоясненияПоОшибке(КраткоеПредставлениеОшибки, КодЯзыка);
	
	Шаблон = НСтр("ru = '%1
	|
	|Возможные причины:
	|%2
	|
	|Способы устранения:
	|%3'", КодЯзыка);
	
	
	ВозможныеПричины = ФорматированныйСписок(ПоясненияПоОшибке.ВозможныеПричины);
	СпособыУстранения = ФорматированныйСписок(ПоясненияПоОшибке.СпособыУстранения);
	
	ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
		Шаблон, КраткоеПредставлениеОшибки, ВозможныеПричины, СпособыУстранения);
	
	Если ВключитьПодробноеПредставлениеОшибки Тогда
		Шаблон = НСтр("ru = '%1
		|
		|Дополнительная информация:
		|%2'", КодЯзыка);
		
		ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(Шаблон, ТекстОшибки, ПодробноеПредставлениеОшибки);
	КонецЕсли;
	
	Возврат ТекстОшибки;
	
КонецФункции

Функция СтрокаСоответствуетШаблону(Знач Строка, Знач Шаблон)
	
	Строка = СтрСоединить(СтрРазделить(Строка, " " + Символы.ПС + Символы.ВК + Символы.Таб, Ложь), " ");
	СтрокаСоответствуетШаблону = Истина;
	
	Для Каждого ЧастиШаблона Из СтрРазделить(Шаблон, "*", Ложь) Цикл
		ФрагментДляПоиска = СтрСоединить(СтрРазделить(ЧастиШаблона, " " + Символы.ПС + Символы.ВК + Символы.Таб, Ложь), " ");
		
		Позиция = СтрНайти(Строка, ФрагментДляПоиска);
		Если Позиция = 0 Тогда
			СтрокаСоответствуетШаблону = Ложь;
			Прервать;
		КонецЕсли;
		
		Строка = Сред(Строка, Позиция + СтрДлина(ФрагментДляПоиска));
	КонецЦикла;
	
	Возврат СтрокаСоответствуетШаблону;
	
КонецФункции

Функция ПодготовитьHTTPЗапрос(АдресРесурса, ПараметрыЗапроса, ПоместитьПараметрыВТелоЗапроса = Истина) Экспорт
	
	Заголовки = Новый Соответствие;
	
	Если ПоместитьПараметрыВТелоЗапроса Тогда
		Заголовки.Вставить("Content-Type", "application/x-www-form-urlencoded");
	КонецЕсли;
	
	Если ТипЗнч(ПараметрыЗапроса) = Тип("Строка") Тогда
		СтрокаПараметров = ПараметрыЗапроса;
	Иначе
		СписокПараметров = Новый Массив;
		Для Каждого Параметр Из ПараметрыЗапроса Цикл
			Значения = Параметр.Значение;
			Если ТипЗнч(Параметр.Значение) <> Тип("Массив") Тогда
				Значения = ОбщегоНазначенияКлиентСервер.ЗначениеВМассиве(Параметр.Значение);
			КонецЕсли;
			
			Для Каждого Значение Из Значения Цикл
				СписокПараметров.Добавить(Параметр.Ключ + "=" + КодироватьСтроку(Значение, СпособКодированияСтроки.КодировкаURL));
			КонецЦикла;
		КонецЦикла;
		СтрокаПараметров = СтрСоединить(СписокПараметров, "&");
	КонецЕсли;
	
	Если Не ПоместитьПараметрыВТелоЗапроса Тогда
		АдресРесурса = АдресРесурса + "?" + СтрокаПараметров;
	КонецЕсли;

	HTTPЗапрос = Новый HTTPЗапрос(АдресРесурса, Заголовки);
	
	Если ПоместитьПараметрыВТелоЗапроса Тогда
		HTTPЗапрос.УстановитьТелоИзСтроки(СтрокаПараметров);
	КонецЕсли;
	
	Возврат HTTPЗапрос;

КонецФункции

Функция ВыполнитьЗапрос(АдресСервера, АдресРесурса, ПараметрыЗапроса, ПоместитьПараметрыВТелоЗапроса = Истина) Экспорт
	
	Результат = Новый Структура;
	Результат.Вставить("ЗапросВыполнен", Ложь);
	Результат.Вставить("ОтветСервера", "");
	
	HTTPЗапрос = ПодготовитьHTTPЗапрос(АдресРесурса, ПараметрыЗапроса, Истина);
	HTTPОтвет = Неопределено;
	
	Прокси = Неопределено;
	Если ОбщегоНазначения.ПодсистемаСуществует("СтандартныеПодсистемы.ПолучениеФайловИзИнтернета") Тогда
		МодульПолучениеФайловИзИнтернета = ОбщегоНазначения.ОбщийМодуль("ПолучениеФайловИзИнтернета");
		Прокси = МодульПолучениеФайловИзИнтернета.ПолучитьПрокси("https");
	КонецЕсли;
	
	Попытка
		Соединение = Новый HTTPСоединение(АдресСервера, , , , Прокси,
			60, ОбщегоНазначенияКлиентСервер.НовоеЗащищенноеСоединение());
		Если ПоместитьПараметрыВТелоЗапроса Тогда
			HTTPОтвет = Соединение.ОтправитьДляОбработки(HTTPЗапрос);
		Иначе
			HTTPОтвет = Соединение.Получить(HTTPЗапрос);
		КонецЕсли;
	Исключение
		ЗаписьЖурналаРегистрации(ИмяСобытияАвторизацияПоПротоколуOAuth(),
			УровеньЖурналаРегистрации.Ошибка, , , ОбработкаОшибок.ПодробноеПредставлениеОшибки(ИнформацияОбОшибке()));
	КонецПопытки;
	
	Если HTTPОтвет <> Неопределено Тогда
		Если HTTPОтвет.КодСостояния <> 200 Тогда
			ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
				НСтр("ru = 'Запрос ""%1"" не выполнен. Код состояния: %2.'"), АдресРесурса, HTTPОтвет.КодСостояния) + Символы.ПС
				+ HTTPОтвет.ПолучитьТелоКакСтроку();
			ЗаписьЖурналаРегистрации(ИмяСобытияАвторизацияПоПротоколуOAuth(),
				УровеньЖурналаРегистрации.Ошибка, , , ТекстОшибки);
		КонецЕсли;
		
		Результат.ЗапросВыполнен = HTTPОтвет.КодСостояния = 200;
		Результат.ОтветСервера = HTTPОтвет.ПолучитьТелоКакСтроку();
	КонецЕсли;
	
	Возврат Результат;
	
КонецФункции

Функция ИмяСобытияАвторизацияПоПротоколуOAuth() Экспорт
	
	Возврат НСтр("ru = 'Работа с почтовыми сообщениями.Авторизация на почтовом сервере'", ОбщегоНазначения.КодОсновногоЯзыка());

КонецФункции

Функция СгенерироватьПроверочныйКод() Экспорт
	
	ПроверочныйКод = "";
	
	Буквы = "abcdefghijklmnopqrstuvwxyz";
	Цифры = "1234567890";
	ДополнительныеСимволы = "-._~";
	
	ДопустимыеСимволы = Буквы + ВРег(Буквы) + Цифры + ДополнительныеСимволы;
	ДлинаСтроки = СтрДлина(ДопустимыеСимволы);
	
	ГенераторСлучайныхЧисел = Новый ГенераторСлучайныхЧисел(ТекущаяУниверсальнаяДатаВМиллисекундах());
	
	Для Счетчик = 1 По 128 Цикл
		Позиция = ГенераторСлучайныхЧисел.СлучайноеЧисло(1, ДлинаСтроки);
		Символ = Сред(ДопустимыеСимволы, Позиция, 1);
		ПроверочныйКод = ПроверочныйКод + Символ;
	КонецЦикла;
	
	Возврат ПроверочныйКод;
	
КонецФункции

Функция КодироватьСтрокуМетодомS256(Строка) Экспорт
	
	ХешированиеДанных = Новый ХешированиеДанных(ХешФункция.SHA256);
	ХешированиеДанных.Добавить(Строка);
	Результат = Base64URLСтрока(ХешированиеДанных.ХешСумма);
	
	Возврат Результат;
	
КонецФункции

Функция Base64URLСтрока(Значение)
	
	Результат = Base64Строка(Значение);
	Результат = СтрЗаменить(Результат, "+", "-");
	Результат = СтрЗаменить(Результат, "/", "_");
	Результат = СтрЗаменить(Результат, "=", "");
	Результат = СтрЗаменить(Результат, Символы.ПС, "");
	
	Возврат Результат;

КонецФункции

Функция ОбновитьТокенДоступа(Знач УчетнаяЗапись, Знач ТокенОбновления)
	
	ЗначенияРеквизитов = ОбщегоНазначения.ЗначенияРеквизитовОбъекта(УчетнаяЗапись, 
		"АдресЭлектроннойПочты, ИмяПочтовогоСервиса");

	Если Не ЗначениеЗаполнено(ЗначенияРеквизитов.ИмяПочтовогоСервиса) Тогда
		ТекстОшибки = НСтр("ru = 'Не указано имя почтового сервиса для авторизации. Необходимо перенастроить почту.'");
		ЗаписьЖурналаРегистрации(ИмяСобытияАвторизацияПоПротоколуOAuth(), УровеньЖурналаРегистрации.Ошибка, , УчетнаяЗапись,
			ТекстОшибки);
		Возврат "";
	КонецЕсли;
	
	СтруктураURI = ОбщегоНазначенияКлиентСервер.СтруктураURI(ЗначенияРеквизитов.АдресЭлектроннойПочты);
	
	УстановитьПривилегированныйРежим(Истина);
	НастройкиАвторизации = Справочники.НастройкиАвторизацииИнтернетСервисов.НастройкиАвторизацииИнтернетСервиса(
		ЗначенияРеквизитов.ИмяПочтовогоСервиса, СтруктураURI.Хост);
	УстановитьПривилегированныйРежим(Ложь);
		
	Если Не ЗначениеЗаполнено(НастройкиАвторизации.ИдентификаторПриложения) Тогда
		ТекстОшибки = НСтр("ru = 'Настройки авторизации Интернет-сервиса ""%1"" не найдены для домена ""%2"". Необходимо перенастроить почту.'");
		ЗаписьЖурналаРегистрации(ИмяСобытияАвторизацияПоПротоколуOAuth(), УровеньЖурналаРегистрации.Ошибка, , УчетнаяЗапись,
			ТекстОшибки);
			Возврат "";
	КонецЕсли;
	
	СтруктураURI = ОбщегоНазначенияКлиентСервер.СтруктураURI(НастройкиАвторизации.АдресПолученияКлюча);
	АдресСервера = СтруктураURI.Хост;
	АдресРесурса = "/" + СтруктураURI.ПутьНаСервере;
	
	ПараметрыЗапроса = Новый Структура;
	ПараметрыЗапроса.Вставить("client_id", НастройкиАвторизации.ИдентификаторПриложения);
	
	Если ЗначениеЗаполнено(НастройкиАвторизации.ИспользоватьПарольПриложения) Тогда
		ПараметрыЗапроса.Вставить("client_secret", НастройкиАвторизации.ПарольПриложения);
	КонецЕсли;
	
	Если ЗначениеЗаполнено(НастройкиАвторизации["ЗапрашиваемыеРазрешения"]) Тогда
		ПараметрыЗапроса.Вставить("scope", НастройкиАвторизации["ЗапрашиваемыеРазрешения"]);
	КонецЕсли;

	ПараметрыЗапроса.Вставить("refresh_token", ТокенОбновления);
	ПараметрыЗапроса.Вставить("grant_type", "refresh_token");
	
	ВремяЗапроса = ТекущаяДатаСеанса();
	
	РезультатЗапроса = ВыполнитьЗапрос(АдресСервера, АдресРесурса, ПараметрыЗапроса);
	
	Попытка
		ПараметрыОтвета = ОбщегоНазначения.JSONВЗначение(РезультатЗапроса.ОтветСервера);
	Исключение
		ПараметрыОтвета = Новый Соответствие;
	КонецПопытки;
	
	ТокенДоступа = ПараметрыОтвета["access_token"];
	СрокДействияТокенаДоступа = ПараметрыОтвета["expires_in"];
	Если ЗначениеЗаполнено(ПараметрыОтвета["refresh_token"]) Тогда
		ТокенОбновления = ПараметрыОтвета["refresh_token"];
	КонецЕсли;
	КодОшибки = ПараметрыОтвета["error"];
	ТекстОшибки = ПараметрыОтвета["error_description"];
	
	Если ЗначениеЗаполнено(КодОшибки) Тогда
		ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
			НСтр("ru = 'Не удалось получить ключи доступа к учетной записи почты %1 по причине:
			|%2
			|Ответ сервера:
			|%3'"), ЗначенияРеквизитов.АдресЭлектроннойПочты, ТекстОшибки, РезультатЗапроса.ОтветСервера);
		ЗаписьЖурналаРегистрации(ИмяСобытияАвторизацияПоПротоколуOAuth(),
			УровеньЖурналаРегистрации.Ошибка, , , ТекстОшибки);

		Возврат "";
	ИначеЕсли Не РезультатЗапроса.ЗапросВыполнен Тогда
		ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
			НСтр("ru = 'Не удалось получить ключи доступа к учетной записи почты %1 по причине:
			|Запрос не выполнен.
			|Ответ сервера:
			|%2'"), ЗначенияРеквизитов.АдресЭлектроннойПочты, РезультатЗапроса.ОтветСервера);
		ЗаписьЖурналаРегистрации(ИмяСобытияАвторизацияПоПротоколуOAuth(), УровеньЖурналаРегистрации.Ошибка, , УчетнаяЗапись,
			ТекстОшибки);
		Возврат "";
	КонецЕсли;
	
	Если ЗначениеЗаполнено(СрокДействияТокенаДоступа) Тогда
		СрокДействияТокенаДоступа = ВремяЗапроса + СрокДействияТокенаДоступа;
	КонецЕсли;
	
	УстановитьПривилегированныйРежим(Истина);

	ОбщегоНазначения.ЗаписатьДанныеВБезопасноеХранилище(УчетнаяЗапись, ТокенДоступа, "ТокенДоступа");
	ОбщегоНазначения.ЗаписатьДанныеВБезопасноеХранилище(УчетнаяЗапись, СрокДействияТокенаДоступа, "СрокДействияТокенаДоступа");
	ОбщегоНазначения.ЗаписатьДанныеВБезопасноеХранилище(УчетнаяЗапись, ТокенОбновления, "ТокенОбновления");
	
	УстановитьПривилегированныйРежим(Ложь);
	
	Возврат ТокенДоступа;
	
КонецФункции

// Параметры:
//  Элемент - РасширениеПоляФормыДляПоляВвода
//
Процедура ОформитьПолеПароля(Элемент) Экспорт
	
	Элемент.РежимПароля = Истина;
	Элемент.КартинкаКнопкиВыбора = БиблиотекаКартинок.ВводимыеСимволыВидны;
	Элемент.КнопкаВыбора = Ложь;
	
КонецПроцедуры

Процедура ПолучениеСтатусовЭлектронныхПисем() Экспорт

	ОбщегоНазначения.ПриНачалеВыполненияРегламентногоЗадания(Метаданные.РегламентныеЗадания.ПолучениеСтатусовЭлектронныхПисем);
	
	ИдентификаторыПисем = Новый ТаблицаЗначений;
	ИдентификаторыПисем.Колонки.Добавить("Отправитель",         Новый ОписаниеТипов("СправочникСсылка.УчетныеЗаписиЭлектроннойПочты"));
	ИдентификаторыПисем.Колонки.Добавить("ИдентификаторПисьма", Новый ОписаниеТипов("Строка",,,,Новый КвалификаторыСтроки(255)));
	ИдентификаторыПисем.Колонки.Добавить("АдресПолучателя",     Новый ОписаниеТипов("Строка",,,,Новый КвалификаторыСтроки(100)));
	
	ПередПолучениемСтатусовПисем(ИдентификаторыПисем);
	
	Если ИдентификаторыПисем.Количество() = 0 Тогда
		Возврат;
	КонецЕсли;
		
	Запрос = Новый Запрос;
	Запрос.Текст = 
		"ВЫБРАТЬ
		|	ИдентификаторыПисем.Отправитель КАК Отправитель,
		|	ИдентификаторыПисем.ИдентификаторПисьма КАК ИдентификаторПисьма,
		|	ИдентификаторыПисем.АдресПолучателя КАК АдресПолучателя
		|ПОМЕСТИТЬ ИдентификаторыПисем
		|ИЗ
		|	&ИдентификаторыПисем КАК ИдентификаторыПисем
		|;
		|
		|////////////////////////////////////////////////////////////////////////////////
		|ВЫБРАТЬ РАЗЛИЧНЫЕ
		|	ИдентификаторыПисем.Отправитель КАК Отправитель,
		|	ИдентификаторыПисем.ИдентификаторПисьма КАК ИдентификаторПисьма,
		|	ИдентификаторыПисем.АдресПолучателя КАК АдресПолучателя
		|ИЗ
		|	ИдентификаторыПисем КАК ИдентификаторыПисем
		|		ЛЕВОЕ СОЕДИНЕНИЕ Справочник.УчетныеЗаписиЭлектроннойПочты КАК УчетныеЗаписиЭлектроннойПочты
		|		ПО ИдентификаторыПисем.Отправитель = УчетныеЗаписиЭлектроннойПочты.Ссылка
		|ГДЕ
		|	ЕСТЬNULL(УчетныеЗаписиЭлектроннойПочты.ИспользоватьДляПолучения, ЛОЖЬ)
		|ИТОГИ ПО
		|	Отправитель";
	
	Запрос.УстановитьПараметр("ИдентификаторыПисем", ИдентификаторыПисем);
	
	РезультатЗапроса = Запрос.Выполнить();
	
	ВыборкаОтправитель = РезультатЗапроса.Выбрать(ОбходРезультатаЗапроса.ПоГруппировкам);
	
	ПараметрыЗагрузкиСообщений = Новый Структура;
	КолонкиТаблицыСообщений = Новый Массив;
	ПоляИнтернетПочтовогоСообщения = РаботаСПочтовымиСообщениями.ПоляИнтернетПочтовогоСообщения();
	КолонкиТаблицыСообщений.Добавить(ПоляИнтернетПочтовогоСообщения.Заголовок);
	КолонкиТаблицыСообщений.Добавить(ПоляИнтернетПочтовогоСообщения.ДатаОтправления);
	КолонкиТаблицыСообщений.Добавить(ПоляИнтернетПочтовогоСообщения.Тексты);
	КолонкиТаблицыСообщений.Добавить(ПоляИнтернетПочтовогоСообщения.Отправитель);
	ПараметрыЗагрузкиСообщений.Вставить("Колонки", КолонкиТаблицыСообщений);

	СтатусыДоставки = Новый ТаблицаЗначений;
	СтатусыДоставки.Колонки.Добавить("Отправитель",        	 Новый ОписаниеТипов("СправочникСсылка.УчетныеЗаписиЭлектроннойПочты"));
	СтатусыДоставки.Колонки.Добавить("ИдентификаторПисьма",  Новый ОписаниеТипов("Строка",,,,Новый КвалификаторыСтроки(255)));
	СтатусыДоставки.Колонки.Добавить("АдресПолучателя",      Новый ОписаниеТипов("Строка",,,,Новый КвалификаторыСтроки(100)));
	СтатусыДоставки.Колонки.Добавить("Статус",               Новый ОписаниеТипов("ПеречислениеСсылка.СтатусыЭлектронныхПисем"));
	СтатусыДоставки.Колонки.Добавить("ДатаИзмененияСтатуса", Новый ОписаниеТипов("Дата"));  
	СтатусыДоставки.Колонки.Добавить("Причина",              Новый ОписаниеТипов("Строка",,,,Новый КвалификаторыСтроки(500)));
	
	Пока ВыборкаОтправитель.Следующий() Цикл
					
		Сообщения = РаботаСПочтовымиСообщениями.ЗагрузитьПочтовыеСообщения(ВыборкаОтправитель.Отправитель, ПараметрыЗагрузкиСообщений);
		
		Выборка = ВыборкаОтправитель.Выбрать();
		
		Пока Выборка.Следующий() Цикл
			Для Каждого Сообщение Из Сообщения Цикл // ИнтернетПочтовоеСообщение
				Если СтрНайти(Сообщение.Заголовок, Выборка.АдресПолучателя) = 0 
					И СтрНайти(Сообщение.Заголовок, Выборка.ИдентификаторПисьма) = 0
					И СтрНайти(Сообщение.Отправитель, "mailer-daemon")= 0 
					И СтрНайти(Сообщение.Заголовок, "prod.outlook.com")= 0 Тогда
					Продолжить;
				КонецЕсли;
				Если СтрНайти(Сообщение.Заголовок, Выборка.ИдентификаторПисьма) > 0 Тогда
					Если СтрНайти(Сообщение.Заголовок, Выборка.АдресПолучателя) > 0 И СтрНайти(Сообщение.Заголовок, "X-Failed-Recipients") > 0  Тогда
						ОтборСтрок = Новый Структура("ИдентификаторПисьма, АдресПолучателя", Выборка.ИдентификаторПисьма, Выборка.АдресПолучателя);
						СуществующиеСтрокиСтатусов = СтатусыДоставки.НайтиСтроки(ОтборСтрок);
						Если СуществующиеСтрокиСтатусов.Количество() > 0 Тогда
							СтрокаСтатусыДоставки = СуществующиеСтрокиСтатусов[0];
						Иначе
							СтрокаСтатусыДоставки = СтатусыДоставки.Добавить(); 
						КонецЕсли;
						СтрокаСтатусыДоставки.Отправитель = ВыборкаОтправитель.Отправитель;
						СтрокаСтатусыДоставки.ИдентификаторПисьма = Выборка.ИдентификаторПисьма;
						СтрокаСтатусыДоставки.АдресПолучателя = Выборка.АдресПолучателя;
						СтрокаСтатусыДоставки.Статус = Перечисления.СтатусыЭлектронныхПисем.НеДоставлено;
						
						НомерСимволаСтрокаПричины = СтрНайти(Сообщение.Заголовок, "X-Mailer-Daemon-Error");
						Если НомерСимволаСтрокаПричины > 0 Тогда 
							НомерСимволаНачалоПричины = НомерСимволаСтрокаПричины + СтрДлина("X-Mailer-Daemon-Error:");
							Причина = Сред(Сообщение.Заголовок, НомерСимволаНачалоПричины);
							НомерСимволаПереносСтроки = СтрНайти(Причина, Символы.Пс);
							Причина = СокрЛП(Лев(Причина, НомерСимволаПереносСтроки));
							Причина = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
								НСтр("ru = 'Письмо не доставлено по причине: %1.'"), Причина);
						Иначе
								Причина = НСтр("ru = 'Письмо не доставлено.'");
						КонецЕсли;
						
						СтрокаСтатусыДоставки.Причина = Причина;
						СтрокаСтатусыДоставки.ДатаИзмененияСтатуса = Сообщение.ДатаОтправления;
						Прервать;
					ИначеЕсли СтрНайти(Сообщение.Заголовок, "Delivery Status Notification") > 0 Или СтрНайти(
						Сообщение.Заголовок, "Disposition-Notification-To") > 0 
						Или СтрНайти(Сообщение.Заголовок, "report-type=delivery-status") > 0 Тогда
						
						ОтборСтрок = Новый Структура("ИдентификаторПисьма, АдресПолучателя", Выборка.ИдентификаторПисьма, Выборка.АдресПолучателя);
						СуществующиеСтрокиСтатусов = СтатусыДоставки.НайтиСтроки(ОтборСтрок);
						Если СуществующиеСтрокиСтатусов.Количество() > 0 Тогда
							Продолжить;
						КонецЕсли;
						
						СтрокаСтатусыДоставки = СтатусыДоставки.Добавить();
						СтрокаСтатусыДоставки.Отправитель = ВыборкаОтправитель.Отправитель;
						СтрокаСтатусыДоставки.ИдентификаторПисьма = Выборка.ИдентификаторПисьма;
						СтрокаСтатусыДоставки.АдресПолучателя = Выборка.АдресПолучателя;
						СтрокаСтатусыДоставки.Статус = Перечисления.СтатусыЭлектронныхПисем.Доставлено;
						СтрокаСтатусыДоставки.ДатаИзмененияСтатуса = Сообщение.ДатаОтправления;
						Продолжить;
					КонецЕсли;
				Иначе
					Если Сообщение.Тексты.Количество() > 0 Тогда
						Для Каждого ТекстПисьма Из Сообщение.Тексты Цикл
							Если ТекстПисьма["ТипТекста"] = "HTML" Тогда
								Продолжить;
							КонецЕсли;
							ОтборСтрок = Новый Структура("ИдентификаторПисьма, АдресПолучателя", Выборка.ИдентификаторПисьма, Выборка.АдресПолучателя);
							СуществующиеСтрокиСтатусов = СтатусыДоставки.НайтиСтроки(ОтборСтрок);
							Если СуществующиеСтрокиСтатусов.Количество() > 0 Тогда
								Прервать;
							КонецЕсли;

							Если СтрНайти(ТекстПисьма["Текст"], Выборка.ИдентификаторПисьма) > 0
								И СтрНайти(ТекстПисьма["Текст"], Выборка.АдресПолучателя) > 0
								И (СтрНайти(ТекстПисьма["Текст"], "this error:") > 0
								Или СтрНайти(ТекстПисьма["Текст"], "Delivery has failed") > 0) Тогда
								СтрокаСтатусыДоставки = СтатусыДоставки.Добавить();
								СтрокаСтатусыДоставки.Отправитель = ВыборкаОтправитель.Отправитель;
								СтрокаСтатусыДоставки.ИдентификаторПисьма = Выборка.ИдентификаторПисьма;
								СтрокаСтатусыДоставки.АдресПолучателя = Выборка.АдресПолучателя;
								СтрокаСтатусыДоставки.Статус = Перечисления.СтатусыЭлектронныхПисем.НеДоставлено;
								
								НомерСимволаНачалоПричины = СтрНайти(ТекстПисьма["Текст"], "this error:");
								Если НомерСимволаНачалоПричины = 0 Тогда
									НомерСимволаНачалоПричины = СтрНайти(ТекстПисьма["Текст"], "Your message");
								КонецЕсли;
								Причина = Сред(ТекстПисьма["Текст"], НомерСимволаНачалоПричины);
								НомерСимволаКонецПричины = СтрНайти(Причина, Символы.ПС,,,2);
								Причина = Сред(Причина, 1, НомерСимволаКонецПричины);
								
								Причина = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
								НСтр("ru = 'Письмо не доставлено по причине: %1.'"), СокрЛП(Причина));
								
								СтрокаСтатусыДоставки.Причина = Причина;
								СтрокаСтатусыДоставки.ДатаИзмененияСтатуса = Сообщение.ДатаОтправления;
								
							ИначеЕсли СтрНайти(ТекстПисьма["Текст"], Выборка.ИдентификаторПисьма) > 0
								И СтрНайти(ТекстПисьма["Текст"], Выборка.АдресПолучателя) > 0 Тогда
								
								СтрокаСтатусыДоставки = СтатусыДоставки.Добавить();
								СтрокаСтатусыДоставки.Отправитель = ВыборкаОтправитель.Отправитель;
								СтрокаСтатусыДоставки.ИдентификаторПисьма = Выборка.ИдентификаторПисьма;
								СтрокаСтатусыДоставки.АдресПолучателя = Выборка.АдресПолучателя;
								СтрокаСтатусыДоставки.Статус = Перечисления.СтатусыЭлектронныхПисем.Доставлено;
								СтрокаСтатусыДоставки.ДатаИзмененияСтатуса = Сообщение.ДатаОтправления;
							ИначеЕсли СтрНайти(ТекстПисьма["Текст"], Выборка.АдресПолучателя) > 0
								И СтрНайти(ТекстПисьма["Текст"], "message could not") Тогда
								
								СтрокаСтатусыДоставки = СтатусыДоставки.Добавить(); 
								СтрокаСтатусыДоставки.Отправитель = ВыборкаОтправитель.Отправитель;
								СтрокаСтатусыДоставки.ИдентификаторПисьма = Выборка.ИдентификаторПисьма;
								СтрокаСтатусыДоставки.АдресПолучателя = Выборка.АдресПолучателя;
								СтрокаСтатусыДоставки.Статус = Перечисления.СтатусыЭлектронныхПисем.НеДоставлено;
								
								НомерСимволаНачалоПричины = СтрНайти(ТекстПисьма["Текст"], Выборка.АдресПолучателя, НаправлениеПоиска.СКонца);
								Причина = Сред(ТекстПисьма["Текст"], НомерСимволаНачалоПричины);
								Причина = СтрЗаменить(Причина, Символы.ВК, "");
								
								Причина = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
								НСтр("ru = 'Письмо не доставлено по причине: %1.'"), СокрЛП(Причина));
								
								СтрокаСтатусыДоставки.Причина = Причина;
								СтрокаСтатусыДоставки.ДатаИзмененияСтатуса = Сообщение.ДатаОтправления;
								
							КонецЕсли;
							Продолжить;
						КонецЦикла;
					КонецЕсли;
				КонецЕсли;
			КонецЦикла;
		КонецЦикла;
	
	КонецЦикла;
	
	ПослеПолученияСтатусовПисем(СтатусыДоставки);
	
КонецПроцедуры

// См. РаботаСПочтовымиСообщениямиПереопределяемый.ПередПолучениемСтатусовПисем
Процедура ПередПолучениемСтатусовПисем(ИдентификаторыПисем) 
	
	ИнтеграцияПодсистемБСП.ПередПолучениемСтатусовПисем(ИдентификаторыПисем);
	РаботаСПочтовымиСообщениямиПереопределяемый.ПередПолучениемСтатусовПисем(ИдентификаторыПисем);  
	
КонецПроцедуры  

// См. РаботаСПочтовымиСообщениямиПереопределяемый.ПослеПолученияСтатусовПисем
Процедура ПослеПолученияСтатусовПисем(СтатусыДоставки)
	
	ИнтеграцияПодсистемБСП.ПослеПолученияСтатусовПисем(СтатусыДоставки);
	РаботаСПочтовымиСообщениямиПереопределяемый.ПослеПолученияСтатусовПисем(СтатусыДоставки);  
	
КонецПроцедуры

#Область Punycode

Функция КодироватьСтрокуСРазделителем(Строка, Разделители = ".")
	МассивПодстрок = СтрРазделить(Строка, Разделители);
	КодированныйАдресХоста = "";
	ПозицияРазделителя = 0;
	Для Каждого Подстрока Из МассивПодстрок Цикл
		ПозицияРазделителя = ПозицияРазделителя + СтрДлина(Подстрока)+1; 
		КодированныйАдресХоста = КодированныйАдресХоста + КодироватьСтрокуPunycode(Подстрока);
		КодированныйАдресХоста = КодированныйАдресХоста + Сред(Строка, ПозицияРазделителя, 1);
	КонецЦикла;
	Возврат КодированныйАдресХоста;
КонецФункции

Функция ДекодироватьСтрокуСРазделителем(Строка, Разделители = ".")
	МассивПодстрок = СтрРазделить(Строка, Разделители);
	ДекодированныйАдресХоста = "";
	ПозицияРазделителя = 0;
	Для Каждого Подстрока Из МассивПодстрок Цикл
		ПозицияРазделителя = ПозицияРазделителя + СтрДлина(Подстрока)+1; 
		ДекодированныйАдресХоста = ДекодированныйАдресХоста + ДекодироватьСтрокуPunycode(Подстрока);
		ДекодированныйАдресХоста = ДекодированныйАдресХоста + Сред(Строка, ПозицияРазделителя, 1);
	КонецЦикла;
	Возврат ДекодированныйАдресХоста;
КонецФункции

// Параметры:
//  Письмо - ИнтернетПочтовоеСообщение
//
Процедура КодироватьАдресаВПисьме(Письмо)
	КодироватьКоллекциюАдресов(Письмо.АдресаУведомленияОПрочтении);
	КодироватьКоллекциюАдресов(Письмо.ОбратныйАдрес);
	КодироватьКоллекциюАдресов(Письмо.Получатели);
	КодироватьКоллекциюАдресов(Письмо.СлепыеКопии);
	Письмо.Отправитель.Адрес = СтрокаВPunycode(Письмо.Отправитель.Адрес);
КонецПроцедуры

// Параметры:
//  КоллекцияАдресов - ИнтернетПочтовыеАдреса
//
Процедура КодироватьКоллекциюАдресов(КоллекцияАдресов)
	Если КоллекцияАдресов <> Неопределено Тогда
		Для Каждого Адрес Из КоллекцияАдресов Цикл
			Адрес.Адрес = СтрокаВPunycode(Адрес.Адрес);
		КонецЦикла;
	КонецЕсли;
КонецПроцедуры

// Параметры:
//  КоллекцияАдресов - ИнтернетПочтовыеАдреса
//
Процедура ДекодироватьКоллекциюАдресов(КоллекцияАдресов)
	Если КоллекцияАдресов <> Неопределено Тогда
		Для Каждого Адрес Из КоллекцияАдресов Цикл
			Адрес.Адрес = PunycodeВСтроку(Адрес.Адрес);
		КонецЦикла;
	КонецЕсли;
КонецПроцедуры

Функция ЭтоСимволASCII(Знач Символ)
	Возврат КодСимвола(Символ) < 128;
КонецФункции

Функция ПорядковыйНомерВСимвол(Знач ПорядковыйНомер)
	Возврат Символ(ПорядковыйНомер + 22 + 75 * (ПорядковыйНомер < 26));
КонецФункции

Функция КодСимволаВПорядковыйНомер(Знач Код)
	Код0 = КодСимвола("0");
	КодA = КодСимвола("a");
	
	Если Код - Код0 < 10 Тогда
		Возврат Код - Код0 + 26;
	ИначеЕсли Код - КодA < 26 Тогда
		Возврат Код - КодA;
	Иначе
		ВызватьИсключение НСтр("ru='Плохие данные на вход'");
	КонецЕсли;
КонецФункции

Функция АдаптацияСмещения(Знач Дельта, Знач ПозицияСимвола, Знач ПерваяАдаптация)
	Дельта = Цел(?(ПерваяАдаптация, Дельта / 700, Дельта / 2));
	Дельта = Дельта + Цел(Дельта / ПозицияСимвола);
	
	ДелительДельты = 36 - 1;
	Порог = Цел(ДелительДельты * 26 / 2);
	Перемещение = 0;
	
	Пока Дельта > Порог Цикл
		Дельта = Цел(Дельта / ДелительДельты);
		Перемещение = Перемещение + 36;
	КонецЦикла;
	
	Возврат Перемещение + Цел((ДелительДельты + 1) * Дельта / (Дельта + 38));
КонецФункции

Функция КодироватьСтрокуPunycode(Знач ВходящаяСтрока)
	Результат = Новый Массив;
	
	Дельта = 0;
	ТекущаяПозиция = 0;
	СимволовНаВывод = 0;
	ТекущийНаибольший = 0;
	СкорректированнаяДельта = 0;
	Перемещение = 0;

	Наибольший = 128;
	Смещение = 72;
	ДлинаСтроки = СтрДлина(ВходящаяСтрока);

	Для ИндексСимвола = 1 По ДлинаСтроки Цикл
		ОчереднойСимвол = Сред(ВходящаяСтрока, ИндексСимвола, 1);
		Если ЭтоСимволASCII(ОчереднойСимвол) Тогда
			Результат.Добавить(ОчереднойСимвол);
			СимволовНаВывод = СимволовНаВывод + 1;
		КонецЕсли;
	КонецЦикла;

	ТекущаяПозиция = СимволовНаВывод;
	Начало = СимволовНаВывод;

	Если СимволовНаВывод = ДлинаСтроки Тогда
		Возврат ВходящаяСтрока;
	КонецЕсли;
	
	ЕстьДефис = ?(Результат.Найти("-") = Неопределено, Ложь, Истина);
	
	Результат.Добавить("-");
	СимволовНаВывод = СимволовНаВывод + 1;

	Пока ТекущаяПозиция < ДлинаСтроки Цикл
		ТекущийНаибольший = 9999999999;
		Для ИндексСимвола = 1 По ДлинаСтроки Цикл
			Код = КодСимвола(ВходящаяСтрока, ИндексСимвола);
			Если Код >= Наибольший И Код < ТекущийНаибольший Тогда
				ТекущийНаибольший = Код;
			КонецЕсли;
		КонецЦикла;
		
		Если ТекущийНаибольший - Наибольший > Цел((9999999999 - Дельта) / (ТекущаяПозиция + 1)) Тогда
			ВызватьИсключение "Переполнение";
		КонецЕсли;
		
		Дельта = Дельта + (ТекущийНаибольший - Наибольший) * (ТекущаяПозиция + 1);
		Наибольший = ТекущийНаибольший;
		
		Для ИндексСимвола = 1 По ДлинаСтроки Цикл
			Код = КодСимвола(ВходящаяСтрока, ИндексСимвола);
			Если Код < Наибольший Тогда
				Дельта = Дельта + 1;
				Если Дельта = 0 Тогда
					ВызватьИсключение "Переполнение";
				КонецЕсли;
			ИначеЕсли Код = Наибольший Тогда
				СкорректированнаяДельта = Дельта;
				Перемещение = 36;
				
				Пока Истина Цикл
					ПредполагаемыйПорядковыйНомер = ?(Перемещение <= Смещение, 1,
						?(Перемещение >= Смещение + 26, 26, Перемещение - Смещение));
					Если СкорректированнаяДельта < ПредполагаемыйПорядковыйНомер Тогда
						Прервать;
					КонецЕсли;
					
					КодированныйСимвол = ПорядковыйНомерВСимвол(ПредполагаемыйПорядковыйНомер 
					+ (СкорректированнаяДельта - ПредполагаемыйПорядковыйНомер) % (36 - ПредполагаемыйПорядковыйНомер));
					Результат.Добавить(КодированныйСимвол);
					
					СкорректированнаяДельта = Цел((СкорректированнаяДельта - ПредполагаемыйПорядковыйНомер) / (36 - ПредполагаемыйПорядковыйНомер));
					Перемещение = Перемещение + 36;
				КонецЦикла;
				
				Результат.Добавить(ПорядковыйНомерВСимвол(СкорректированнаяДельта));
				
				Смещение = АдаптацияСмещения(Дельта, ТекущаяПозиция + 1, ТекущаяПозиция = Начало);
				Дельта = 0;
				ТекущаяПозиция = ТекущаяПозиция + 1;
			КонецЕсли;
		КонецЦикла;
		
		Дельта = Дельта + 1;
		Наибольший = Наибольший + 1;
	КонецЦикла;
	КодированнаяСтрока = "xn--" + СтрСоединить(Результат);
	
	Если НЕ ЕстьДефис Тогда
		КодированнаяСтрока = СтрЗаменить(КодированнаяСтрока, "---", "--");
	КонецЕсли;
	
	Возврат КодированнаяСтрока;
КонецФункции

Функция ДекодироватьСтрокуPunycode(Знач КодированнаяСтрока)
	Если Не СтрНачинаетсяС(КодированнаяСтрока, "xn--") Тогда
		Возврат КодированнаяСтрока;
	Иначе
		КодированнаяСтрока = СтрЗаменить(КодированнаяСтрока, "xn--", "");
	КонецЕсли;
	Результат = Новый Массив;
	Код = 128;
	ПозицияВставки = 0;
	Смещение = 72;
	
	ПозицияЧтения = СтрНайти(КодированнаяСтрока, "-", НаправлениеПоиска.СКонца);
	Если ПозицияЧтения > 0 Тогда
		Для ИндексСимвола = 1 По ПозицияЧтения-1 Цикл
			ОчереднойСимвол = Сред(КодированнаяСтрока, ИндексСимвола, 1);
			Если НЕ ЭтоСимволASCII(ОчереднойСимвол) Тогда
				ВызватьИсключение НСтр("ru='Плохие данные на вход'");
			КонецЕсли;
			Результат.Добавить(ОчереднойСимвол);
		КонецЦикла;
	КонецЕсли;
	ПозицияЧтения = ПозицияЧтения + 1;

	Пока ПозицияЧтения <= СтрДлина(КодированнаяСтрока) Цикл
		ПредыдущаяПозицияВставки = ПозицияВставки;
		МультипликаторПозицииВставки = 1;
		Перемещение = 36;
		
		Пока Истина Цикл
			Если ПозицияЧтения > СтрДлина(КодированнаяСтрока) Тогда
				ВызватьИсключение НСтр("ru='Плохие данные на вход'");
			КонецЕсли;
			
			КодОчередногоСимвола = КодСимвола(Сред(КодированнаяСтрока, ПозицияЧтения, 1));
			ПозицияЧтения = ПозицияЧтения + 1;
			
			ПорядковыйНомерОчередногоСимвола = КодСимволаВПорядковыйНомер(КодОчередногоСимвола);
			Если ПорядковыйНомерОчередногоСимвола > (9999999999 - ПозицияВставки) / МультипликаторПозицииВставки Тогда
				ВызватьИсключение НСтр("ru='Переполнение'");
			КонецЕсли;
			
			ПозицияВставки = ПозицияВставки + ПорядковыйНомерОчередногоСимвола * МультипликаторПозицииВставки;
			
			ПорядковыйНомер = 0;
			Если Перемещение <= Смещение Тогда
				ПорядковыйНомер = 1;
			ИначеЕсли Перемещение >= Смещение + 26 Тогда
				ПорядковыйНомер = 26;
			Иначе
				ПорядковыйНомер = Перемещение - Смещение;
			КонецЕсли;
			Если ПорядковыйНомерОчередногоСимвола < ПорядковыйНомер Тогда
				Прервать;
			КонецЕсли;
			
			МультипликаторПозицииВставки = МультипликаторПозицииВставки * (36 - ПорядковыйНомер);
			Перемещение = Перемещение + 36;
		КонецЦикла;
		
		Если (ПозицияВставки / (Результат.Количество() + 1)) > (9999999999 - Код) Тогда
			ВызватьИсключение НСтр("ru='Переполнение'");
		КонецЕсли;
		
		Смещение = АдаптацияСмещения(ПозицияВставки - ПредыдущаяПозицияВставки, Результат.Количество() + 1, ПредыдущаяПозицияВставки = 0);

		Код = Код + цел(ПозицияВставки / (Результат.Количество() + 1));
		ПозицияВставки = ПозицияВставки % (Результат.Количество() + 1);
		Результат.Вставить(ПозицияВставки, Символ(Код));
		ПозицияВставки = ПозицияВставки + 1;
	КонецЦикла;

	Возврат СтрСоединить(Результат);
КонецФункции

// Декодирует строку по алгоритму Punycode
// 
// Параметры:
//  Строка - Строка - кодированная строка
// 
// Возвращаемое значение:
//  Строка - декодированная строка
//
Функция PunycodeВСтроку(Знач Строка) Экспорт
	СтруктураURI = ОбщегоНазначенияКлиентСервер.СтруктураURI(Строка);
	АдресХоста = СтруктураURI.Хост;
	ДекодированныйАдресХоста = ДекодироватьСтрокуСРазделителем(АдресХоста);
	Результат = СтрЗаменить(Строка, АдресХоста, ДекодированныйАдресХоста);
	
	Логин = СтруктураURI.Логин;
	ДекодированныйЛогин = ДекодироватьСтрокуСРазделителем(Логин);
	Результат = СтрЗаменить(Результат, Логин, ДекодированныйЛогин);
		
	Возврат Результат;
КонецФункции

Функция АдресаСерверовDNS() Экспорт
	
	Результат = Новый Массив;
	
	Если Метаданные.ОбщиеМодули.Найти("РаботаСПочтовымиСообщениямиСлужебныйЛокализация") <> Неопределено Тогда
		МодульРаботаСПочтовымиСообщениямиСлужебныйЛокализация = ОбщегоНазначения.ОбщийМодуль("РаботаСПочтовымиСообщениямиСлужебныйЛокализация");
		МодульРаботаСПочтовымиСообщениямиСлужебныйЛокализация.ПриПолученииАдресовСерверовDNS(Результат);
		Возврат Результат;
	КонецЕсли;
	
	Результат.Добавить("8.8.8.8"); // dns.google
	Результат.Добавить("8.8.4.4"); // dns.google
	
	Возврат Результат;
	
КонецФункции

Функция АдресФайлаСНастройками() Экспорт
	
	АдресФайла = "https://downloads.v8.1c.eu/content/common/settings/mailservers.json";
	
	Если Метаданные.ОбщиеМодули.Найти("РаботаСПочтовымиСообщениямиСлужебныйЛокализация") <> Неопределено Тогда
		МодульРаботаСПочтовымиСообщениямиСлужебныйЛокализация = ОбщегоНазначения.ОбщийМодуль("РаботаСПочтовымиСообщениямиСлужебныйЛокализация");
		МодульРаботаСПочтовымиСообщениямиСлужебныйЛокализация.ПриПолученииАдресаФайлаСНастройками(АдресФайла);
	КонецЕсли;

	Возврат АдресФайла;
		
КонецФункции

Функция АдресФайлаСОписаниемОшибок()
	
	АдресФайла = "https://downloads.v8.1c.eu/content/common/settings/mailerrors.json";
	
	Если Метаданные.ОбщиеМодули.Найти("РаботаСПочтовымиСообщениямиСлужебныйЛокализация") <> Неопределено Тогда
		МодульРаботаСПочтовымиСообщениямиСлужебныйЛокализация = ОбщегоНазначения.ОбщийМодуль("РаботаСПочтовымиСообщениямиСлужебныйЛокализация");
		МодульРаботаСПочтовымиСообщениямиСлужебныйЛокализация.ПриПолученииАдресаФайлаСОписаниемОшибок(АдресФайла);
	КонецЕсли;

	Возврат АдресФайла;
	
КонецФункции

Функция АдресВнешнегоРесурса()
	
	АдресВнешнегоРесурса = "downloads.v8.1c.eu";
	
	Если Метаданные.ОбщиеМодули.Найти("РаботаСПочтовымиСообщениямиСлужебныйЛокализация") <> Неопределено Тогда
		МодульРаботаСПочтовымиСообщениямиСлужебныйЛокализация = ОбщегоНазначения.ОбщийМодуль("РаботаСПочтовымиСообщениямиСлужебныйЛокализация");
		МодульРаботаСПочтовымиСообщениямиСлужебныйЛокализация.ПриПолученииАдресаВнешнегоРесурса(АдресВнешнегоРесурса);
	КонецЕсли;
	
	Возврат АдресВнешнегоРесурса;
	
КонецФункции

#КонецОбласти

#КонецОбласти